Generics are only supported on version 2.0 and above of the Microsoft .NET framework, as well as version 2.0 of the compact framework.
2. Can I Use Generics in Web Services?
Unfortunately, no. Web services have to expose a WSDL-based contract. Such contracts are always limited by the expressiveness of the message format being used. For example, HTTP-GET based web services only support primitive types such as int or string, but not complex types like a DataSet. SOAP-based web services are more capable, but SOAP has no ability to represent generic type parameters. As a result, at present, you cannot define web services that rely on generic types. That said, you can define .NET web services that rely on closed constructed generic types, for example:
[C#]
public class MyWebService
{
[WebMethod]
public List
{
List
cities.Add("New York");
cities.Add("San Francisco");
cities.Add("London"); return cities;
}
}
In the above example, List
3. Can I Use Generics in Enterprise Services?
Unfortunately, no. All methods and interfaces on a ServicedComponent-derived class must be COM-visible. The COM type system is IDL, and IDL does not support type parameters.
4. Can I Use Generics in Indigo?
Unfortunately, no. SOAP has no ability to represent generic type parameters, and so all methods and interfaces on an indigo service contract or service class can only use primitive types such as integers or strings, or specific known types that provide a data contract. As a result, at present, you cannot define Indigo services that rely on generic types, that is, services that leave it up to the service consumer to specify the types to use when invoking the service.
5. Can I Use Generics in .NET Remoting?
Yes. You can expose generic types as remote objects, for example:
[C#]
public class MyRemoteClass
Type serverType = typeof(MyRemoteClass
RemotingConfiguration.RegisterWellKnownServiceType(serverType, "Some URI", WellKnownObjectMode.SingleCall);
Note that the specific type arguments used must be a marshalable type, that is, either serializable or derived from MarshalByRefObject. Consequently, a generic remote type will typically place a derivation constraint from MarshalByRefObject on its generic type parameters when expecting reference type parameters:
[C#]
public class MyRemoteClass
To administratively register a generic type, provide the type arguments in double square brackets.
For example, to register the class MyRemoteClass
The double square brackets is required in case you need to specify multiple type arguments, in which case, each type arguments would be encased in a separate pair of brackets, separated by a comma. For example, to register the class MyRemoteClass
Creating a new instance of generic remote objects is done just as with non-generic remote objects.
6. Can I Use Visual Studio 2003 or the .NET Framework 1.1 to Create Generics?
Unfortunately no. Generics are only supported on version 2.0 and above of the Microsoft .NET framework. Code that relies on generics must run on version 2.0 of the CLR. Because of the way the CLR version unification works, a run-time process can only load a single version of the CLR. Consequently, a process that loaded version 1.1 of the CLR cannot use generic types. If you must use generic types from .NET 1.1, you can use the following work-around: First, wrap the generic types with object-based types (at the expense of course of the benefits of using generics). Next, load the wrapper classes in a separate process which loads version 2.0 of the CLR, and provide remote access to the wrapper classes to legacy clients in process that use version 1.1 of the CLR. For remote communication you can use any number of cross-process communication mechanisms, such as Remoting, Enterprise Services, sockets, etc.
6. What Environment Do I Need to Use Generics?
To deploy and run code that uses generics you need version 2.0 or higher of the .NET runtime.
7. Can I Use Generics on the Compact Framework?
Yes. The .NET Compact Framework version 2.0 supports generics. Like most other things with the .NET Compact Framework, the generics support is very close but not exactly the same as the normal .NET Framework, due to performance and schedule constrains. You can use generics with both C# and Visual Basic for the compact framework. The compact framework does apply certain limitations on generics, the notable ones are:
· The compact framework does not verify constraints are runtime, only at compile time.
· You can only have up to 8 generic type parameters per generic type.
· You cannot use reflection on unbounded generic types.
8. Which .NET Languages Support Generics and How?
Both C# 2.0 and Visual Basic 2005 support defining and consuming generics. Visual C++ 2005 also supports generics in addition to classic C++ templates. Visual J# 2005 supports consuming generic types but not defining them. At present, it is not known of other vendors besides Microsoft that added generics support for their languages.
9. Where Does the .NET Framework Itself Use Generics?
Version 2.0 of the .NET Framework makes use of generics in three main areas: The System namespace added a large set of static generic methods to the Array type. These methods automate and streamline common manipulations of and interactions with arrays. The System namespace also defined a number of generic utility delegates, which are used by the Array type and the List
The System.Collections.Generic namespace defines generic collection interfaces, collections and iterator classes, similar to the old, non generic ones available in the System.Collections namespace. The System.Collections.Generic namespace also defines a few generic helper classes and structures.
The System.ComponentModel namespace defines the class BindingList
The System.Collections.ObjectModel namespace defines a few types such as Collection
Finally, all the types that supported IComparable in .NET 1.1 support IComparable
10. What Are the Generic Collection Classes?
The System.Collections.Generic namespace contains the majority of the new generic collections. These collections are by and large the generic reincarnation of the collections available in the System.Collections namespace. For example, there is a generic Stack
[C#]
public class List
The System.ComponentModel namespace defines the type BindingList
[C#]
public class BindingList
{
public event ListChangedEventHandler ListChanged;
public event AddingNewEventHandler AddingNew;
public BindingList();
public BindingList(List
public T AddNew();
//More members
}
BindingList
The System.Collections.ObjectModel namespace defines the types Collection
Finally, the System namespace defines the ArraySegment
The following table lists the generic collections and their supporting types, including mapping the generic collections to those of System.Collections or other namespaces when applicable.
Type
Namespace
Non-Generic Equivalent
Comment
ArraySegment
System
-
Used to obtain a generic-based segment of a provided array
BindingList
System.ComponentModel
-
Linked list that fires state changes events
Collection
System.Collections.ObjectModel
Collection
Non abstract base class for other collections
Comparer
System.Collections.Generic
Comparer
Implements IComparer
Dictionary
System.Collections.Generic
HashTable
Implements IDictionary
EqualityComparer
System.Collections.Generic
-
Abstract class implementing IEqualityComparer
ICollection
System.Collections.Generic
ICollection
Count and synchronization for a collection
IComparer
System.Collections.Generic
IComparer
Compares two specified values
IDictionary
System.Collections.Generic
IDictionary
Interface for a collection of key/value pairs
IEnumerable
System.Collections.Generic
IEnumerable
Returns an IEnumerator
IEnumerator
System.Collections.Generic
IEnumerator
Iterating over a collection
IEqualityComparer
System.Collections.Generic
IEqualityComparer
(.NET 2.0 only)
Equates two specified values.
IList
System.Collections.Generic
IList
Implemented by list collections or access by index
KeyedCollection
System.Collections.ObjectModel
-
Base class for keyed collections
KeyValuePair
System.Collections.Generic
-
Container for key/value pair
LinkedList
System.Collections.Generic
-
A true linked list
LinkedListNode
System.Collections.Generic
-
Used by LinkedList
List
System.Collections.Generic
ArrayList
Impalements IList
Queue
System.Collections.Generic
Queue
A queue
ReadOnlyCollection
System.Collections.ObjectModel
ReadOnlyCollectionBase
Base class for read-only collections
SortedDictionary
System.Collections.Generic
SortedList
Implements IDictionary
SortedList
System.Collections.Generic
SortedList
A sorted linked list over an array and a hash table.
Stack
System.Collections.Generic
Stack
A stack
11. What Are the Generic Delegates?
The System namespace defines five new generic delegates. The first is EventHandler
[C#]
public delegate void EventHandler
EventHandler
[C#]
public delegate void EventHandler(object sender, EventArgs e)
But in addition, EventHandler
[C#]
public class MouseEventArgs : EventArgs {...}
public delegate void MouseEventHandler(object sender,MouseEventArgs e);
void OnMyMouseEvent(object sender,MouseEventArgs e) {...}
//Instead of:
MouseEventHandler handler += OnMyMouseEvent;
//You can write:
EventHandler
The other four generic delegates found in the System namespace are designed to be used in conjunction with the static generic methods of Array or the List
[C#]
public delegate void Action
generic
public delegate void Action(T t);
generic
public delegate int Comparison(T x, T y);
generic
public delegate U Converter(T from);
generic
public delegate bool Predicate(T t);
For example, here is using the Action
[C#]
string[] cities = {"New York","San Francisico","London"};
Action
12. What Are the Generic Methods of System.Array?
The System.Array type is extended with many generic static methods. The generic static methods are designed to automate and streamline common tasks of working with arrays, such as iterating over the array and performing an action on each element, scanning the array looking for a value that matches a certain criteria (a predicate), converting and sorting the array, and so on. Below is a partial listing of these static methods:
[C#]
public abstract class Array
{
//Partial listing of the static methods:
public static ReadOnlyCollection
public static int BinarySearch
public static int BinarySearch
comparer);
public static U[] ConvertAll
public static T Find
public static T[] FindAll
public static int FindIndex
public static void ForEach
public static int IndexOf
public static void Sort
public static void Sort
}
Most of these static generic methods work with the four generic delegates defined in the System namespace:
[C#]
public delegate void Action
public delegate int Comparison
public delegate U Converter
public delegate bool Predicate
For example, suppose the array roles contains all the roles a user plays at your application, and you would like to find out if the user is a member or a specified role.
[C#]
bool IsInRole(string role)
{
string[] roles = GetRoles();
Predicate
{
return roleToMatch == role;
};
return Array.Exists(roles,exists);
}
string[] GetRoles() {...}
The Array.Exists() method defined as:
[C#]
public static bool Exists
takes a single type parameter (the type of the array). The compiler can infer the type automatically, so there is no need to specify that. The second parameter is a generic delegate of type Predicate
To demystify how those various methods work, here is how Array.Exist() could be implemented:
[C#]
public abstract class Array
{
public static bool Exists
{
if(array == null)
{
throw new ArgumentNullException("array");
}
if(match == null)
{
throw new ArgumentNullException("match");
}
foreach(T t in array)
{
if(match(t))
{ return true; }
}
return false;
} //Rest of the methods }
13. What Are the Generic Methods of List
Besides implementing IList
[C#]
public class List
{
//Partial listing of the generic helper methods:
public List ConvertAll(Converter
public bool Exists(Predicate
public T Find(Predicate
public List
public int FindIndex(Predicate
public T FindLast(Predicate
public void ForEach(Action
public int LastIndexOf(T item);
public void Sort(Comparison
public T[] ToArray(); //More members
}
Most of these helper generic methods works with the four generic delegates defined in the System namespace:
[C#]
public delegate void Action
public delegate int Comparison
public delegate U Converter
public delegate bool Predicate
The List
[C#]
int[] numbers = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
List
Action
{
Trace.WriteLine(number);
};
Predicate
{
switch(number)
{
case 1:case 2:case 3:case 5:case 7:
case 11:case 13:case 17:case 19:
return true;
default:
return false;
}
};
list.ForEach(trace);
List
primes.ForEach(trace);
14. What Are Nullable Types?
Unlike reference types, you cannot assign a null into a value type. This is often a problem when interacting with code that interprets a null as having no value, rather than no-reference. The canonical example is database null values in columns that have representation as types such as int or DateTime. To address that, the System namespace provides the structure Nullable
[C#]
public interface INullableValue
{
bool HasValue{get;}
object Value{get;}
}
[Serializable] public struct Nullable
{
public Nullable(T value);
public bool HasValue{get;}
public T Value{get;}
public T GetValueOrDefault();
public T GetValueOrDefault(T defaultValue);
public bool Equals(Nullable
public static implicit operator Nullable
public static explicit operator T(Nullable
//More members
}
Because the Nullable
[C#]
Nullable
Debug.Assert(number.HasValue);
number = null;
Debug.Assert(number.HasValue == false);
Debug.Assert(number.Equals(null));
Once a null is assigned to a nullable type, you can still access it to verify if it has a value, via the HasValue property, or just equate it to null.
In C# and Visual Basic, you can even use the underlying value type's operators on a nullable type:
[C#]
Nullable
The reason this is possible is because the compiler is capable of verifying that the underlying type supported the operator, and applying it on the value stored in the structure. This is called lifted operators.
The Nullable
[C#]
Nullable
int number = (int)nullableNumber;
Debug.Assert(number == 123);
number = 456;
nullableNumber = number;
Debug.Assert(nullableNumber.Equals(456));
Note that using Nullable
[C#]
//This will not compile: Nullable nullable
You can use the overloaded methods GetValueOrDefault() of Nullable
[C#]
Nullable
DateTime value = time.GetValueOrDefault();
Debug.Assert(value.ToString() == "1/1/0001 12:00:00 AM");
The System namespace also defines the static helper class Nullable and the helper class NullableConverter, but those are not needed usually.
The C# 2.0 compiler supports shorthand for Nullable
int? number = 123;
Debug.Assert(number.HasValue);
number = null;
Debug.Assert(number.HasValue == false);
Note that the type declared by the ? modifier is identical to that created using Nullable
Debug.Assert(typeof(int?) == typeof(Nullable
As with using Nullable
int? number1 = 123;
int? number2 = null;
int? sum = number1 + number2;
Debug.Assert(sum == null);
Using the ? modifier is the common way of declaring and using nullable variables in C#. You can even pass nullable types as type arguments for generic types:
IList
list.Add(3);
list.Add(null);
C# 2.0 also provides the null coalescing operator via the ?? operator.
c = a ?? b;
The result of applying the ?? operator on two operands returns the left hand side operand (a) if it is not null, and the right operand (b)otherwise. While b can of course be null too, you typically use the ?? operator to supply a default value in case a is null.
15. How Do I Reflect Generic Types?
Like most other things done with reflection, you use the class Type. Type can represent generic types with specific type arguments (called bounded types), or unspecified (unbounded) types.
[C#]
Both typeof and GetType() can operate on type parameters:
public class MyClass
{
public void SomeMethod(T t)
{
Type type = typeof(T);
Debug.Assert(type == t.GetType());
}
}
In addition the typeof operator can operate on unbound generic types (generic types that do not have yet specific type arguments). For example:
public class MyClass
{}
Type unboundedType = typeof(MyClass<>);
Trace.WriteLine(unboundedType.ToString());
//Writes: MyClass`1[T]
The number 1 being traced is the number of generic type parameters of the generic type used. Note the use of the empty <>. To operate on an unbound generic type with multiple type parameters, use a , in the <>:
public class LinkedList
{...}
Type unboundedList = typeof(LinkedList<,>);
Trace.WriteLine(unboundedList.ToString());
//Writes: LinkedList`2[K,T]
[Visual Basic]
Both GetType() and Object.GetType() can operate on type parameters:
Public Class SomeClass(Of T) Public Sub SomeMethod(ByVal t As T) Dim theType As Type = GetType(T) Debug.Assert((theType Is t.GetType)) End Sub End Class
To support generics, Type has special methods and properties designed to provide reflection information about the generic aspects of the type:
[C#]
public abstract class Type : //Base types
{
public virtual bool ContainsGenericParameters{get;}
public virtual GenericParameterAttributes GenericParameterAttributes{get;}
public virtual int GenericParameterPosition{get;}
public virtual bool IsGenericType{get;}
public virtual bool IsGenericParameter{get;}
public virtual bool IsGenericTypeDefinition{get;}
public virtual Type[] GetGenericArguments();
public virtual Type[] GetGenericParameterConstraints();
public virtual Type GetGenericTypeDefinition();
public virtual Type MakeGenericType(params Type[] typeArguments);
//Rest of the members
}
The most useful of these new members are the IsGenericType property, the GetGenericArguments() and GetGenericTypeDefinition() methods. As its name indicates, IsGenericType is set to true if the type represented by the Type object uses generic type parameters. GetGenericArguments() returns an array of types corresponding to the type arguments used. GetGenericTypeDefinition() returns a Type representing the generic form of the underlying type. The following example demonstrates using these generic-handling Type members to obtain generic reflection information on a generic linked list.
[C#]
public class LinkedList
{...}
LinkedList
Type boundedType = list.GetType();
Trace.WriteLine(boundedType.ToString());
//Writes:
LinkedList`2[System.Int32,System.String] Debug.Assert(boundedType.IsGenericType);
Type[] parameters = boundedType.GetGenericArguments();
Debug.Assert(parameters.Length == 2);
Debug.Assert(parameters[0] == typeof(int));
Debug.Assert(parameters[1] == typeof(string));
Type unboundedType = boundedType.GetGenericTypeDefinition(); Trace.WriteLine(unboundedType.ToString());
//Writes: LinkedList`2[K,T]
No comments:
Post a Comment