This link has been bookmarked by 17 people . It was first bookmarked on 12 Aug 2008, by Darren Wallace.
-
06 Apr 10
-
Generics are the most powerful feature of C# 2.0. Generics allow you to define type-safe data structures, without committing to actual data types. This results in a significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type-specific code
-
there are two problems with Object-based solutions. The first issue is performance. When using value types, you have to box them in order to push and store them, and unbox the value types when popping them off the stack. Boxing and unboxing incurs a significant performance penalty in their own right, but it also increases the pressure on the managed heap, resulting in more garbage collections, which is not great for performance either. Even when using reference types instead of value types, there is still a performance penalty because you have to cast from an Object to the actual type you interact with and incur the casting cost:
-
The second (and often more severe) problem with the Object-based solution is type safety. Because the compiler lets you cast anything to and from Object, you lose compile-time type safety.
-
solving the performance and type-safety problems this way introduces a third, and just as serious problem—productivity impact.
-
Generics allow you to define type-safe classes without compromising type safety, performance, or productivity.
-
use the < and > brackets, enclosing a generic type parameter.
-
When using a generic stack, you have to instruct the compiler which type to use instead of the generic type parameter T, both when declaring the variable and when instantiating it:
-
T is the generic type parameter (or type parameter) while the generic type is the Stack<T>. The int in Stack<int> is the type argument.
-
On the surface C# generics look syntactically similar to C++ templates, but there are important differences in the way they are implemented and supported by the compiler
-
In some C++ compilers, until you use a template class with a specific type, the compiler does not even compile the template code.
-
may results in code bloating, increasing both the load time and the memory footprint.
-
In .NET 2.0, generics have native support in IL (intermediate language) and the CLR itself.
-
the actual machine code produced depends on whether the specified types are value or reference type.
-
f the client specifies a reference type, then the JIT compiler replaces the generic parameters in the server IL with Object, and compiles it into native code.
-
Because the generic code does not force the boxing and unboxing of value types, or the down casting of reference types, performance is greatly improved.
-
The default value for reference types is null, and the default value for value types (such as integers, enum, and structures) is a zero whitewash (filling the structure with zeros).
-
Whenever you declare a variable of a type that uses generics, you must specify the types to use.
-
Sometimes is it useful to alias a particular combination of specific types. You can do that through the using statement, as shown in Code block 4. Note that the scope of aliasing is the scope of the file, so you have to repeat aliasing across the project files in the same way you would with using namespaces.
-
using List = LinkedList<int,string>;
-
List list = new List();
-
With C# generics, the compiler compiles the generic code into IL independent of any type arguments that the clients will use. As a result, the generic code could try to use methods, properties, or members of the generic type parameters that are incompatible with the specific type arguments the client uses. This is unacceptable because it amounts to lack of type safety.
-
In C# you need to instruct the compiler which constraints the client-specified types must obey in order for them to be used instead of the generic type parameters.
-
There are three types of constraints. A derivation constraint indicates to the compiler that the generic type parameter derives from a base type such an interface or a particular base class. A default constructor constraint indicates to the compiler that the generic type parameter exposes a default public constructor (a public constructor with no parameters). A reference/value type constraint constrains the generic type parameter to be a reference or a value type. A generic type can employ multiple constraints, and you even get IntelliSense reflecting the constraints when using the generic type parameter, such as suggesting methods or members from the base type.
-
derivation constraint
-
if(current.Key == key)
The line above will not compile because the compiler does not know whether K (or the actual type supplied by the client) supports the == operator. For example, structs by default do not provide such an implementation. You could try to overcome the == operator limitation by using the IComparable interface:
-
Derivation Constraints
-
Use the where keyword on the generic type parameter followed by a derivation colon to indicate to the compiler that the generic type parameter implements a particular interface.
-
In C# 2.0 you use the where reserved keyword to define a constraint.
-
where K : IComparable
-
Note that even though the constraint allows you to use IComparable, it does not eliminate the boxing penalty when the key used is a value type, such as an integer. To overcome this, the System.Collections.Generic namespace defines the generic interface IComparable<T>:
-
IComparable<K>
-
ll the types that supported IComparable in .NET 1.1 support IComparable<T> in .NET 2.0. This enables the use for keys of common types such as int, string, Guid, DateTime, and so on.
-
n C# 2.0, all constraints must appear after the actual derivation list of the generic class.
-
where K : IComparable<K>
-
the base class you constrain cannot be a sealed class or a static class, and the compiler enforces that. In addition, you cannot constrain System.Delegate or System.Array as a base class.
-
You can constrain both a base class and one or more interfaces, but the base class must appear first in the derivation constraint list:
-
C# does allow you to specify another generic type parameter as a constraint:
-
internal types can use public types:
-
Constructor Constraint
-
Suppose you want to instantiate a new generic object inside a generic class.
-
public default constructor.
-
new()
-
You can combine the constructor constraint with derivation constraint, provided the constructor constraint appears last in the constraint list:
-
where K : IComparable<K>,new()
-
You can constrain a generic type parameter to be a value type (such as an int, a bool, and enum) or any custom structure using the struct constraint:
-
where T : struct
-
Similarly, you can constrain a generic type parameter to be a reference type (a class) using the class constraint:
-
where T : class
-
The reference/value type constraint cannot be used with base class constraint, because a base class constraint implies a class. Similarly, you cannot use the struct and the default constructor constraint, because a default constructor constraint too implies as class. Though you can use the class and the default constructor constraint, it adds no value. You can combine the reference/value type constraint with an interface constraint, as long as the reference/value type constraint appears first in the constraint list.
-
The C# compiler only lets you implicitly cast generic type parameters to Object, or to constraint-specified types, as shown in Code block 5. Such implicit casting is type safe because any incompatibility is discovered at compile-time.
-
The compiler lets you explicitly cast generic type parameters to any other interface, but not to a class:
-
However, you can force a cast from a generic type parameter to any other type using a temporary Object variable:
-
The is operator returns true if the generic type parameter is of the queried type, and as will perform a cast if the types are compatible, and will return null otherwise. You can use is and as on both generic type parameters and on generic classes with specific type arguments.
-
When deriving from a generic base class, you must provide a type argument instead of the base-class's generic type parameter:
-
<int>
-
If the subclass is generic, instead of a concrete type argument, you can use the subclass generic type parameter as the specified type for the generic base class:
-
When using the subclass generic type parameters, you must repeat any constraints stipulated at the base class level at the subclass level. For example, derivation constraint:
-
: BaseClass<T> where T : ISomeInterface
-
where T : new()
-
where T : new()
-
A base class can define virtual methods whose signatures use generic type parameters. When overriding them, the subclass must provide the corresponding types in the method signatures:
-
virtual T SomeMethod()
-
override int SomeMethod()
-
If the subclass is generic it can also use its own generic type parameters for the override:
-
You can define generic interfaces, generic abstract classes, and even generic abstract methods. These types behave like any other generic base type:
-
it is impossible to use operators such as + or += on generic type parameters.
-
C# 2.0 does not have operator constraints:
-
return arg1 + arg2;//Does not compile
-
Nonetheless, you can compensate using abstract methods (or preferably interfaces) by defining generic operations. Since an abstract method cannot have any code in it, you can specify the generic operations at the base class level, and provide a concrete type and implementation at the subclass level:
-
This is an important capability because it allows you to call the method with a different type every time, which is very handy for utility classes.
-
You can define method-specific generic type parameters even if the containing class does not use generics at all:
-
This ability is for methods only. Properties or indexers can only use generic type parameters defined at the scope of the class.
-
<int>
-
allows omitting the type specification altogether:
-
obj.MyMethod(3);
-
This ability is called generic type inference. Note that the compiler cannot infer the type based on the type of the returned value alone:
-
When a method defines its own generic type parameters, it can also define constraints for these types:
-
where T : IComparable<T>
-
However, you cannot provide method-level constraints for class-level generic type parameters. All constraints for class-level generic type parameters must be defined at the class scope.
-
When overriding a virtual method that defines generic type parameters, the subclass method must redefine the method-specific generic type parameter:
-
The subclass implementation must repeat all constraints that appeared at the base method level:
-
Note that the method override cannot define new constraints that did not appear at the base method.
-
In addition, if the subclass method calls the base class implementation of the virtual method, it must specify the type argument to use instead of the generic base method type parameter. You can either explicitly specify it yourself or rely on type inference if it is available:
-
C# allows you to define static methods that use generic type parameters. However, when invoking such a static method, you need to provide the concrete type for the containing class at the call site
-
MyClass<T>
-
static T SomeMethod(T t)
-
MyClass<int>.SomeMethod(3);
-
Static methods can define method-specific generic type parameters and constraints, similar to instance methods. When calling such methods, you need to provide the method-specific types at the call site, either explicitly:
-
Or rely on type inference when possible:
-
Generic static methods are subjected to all constraints imposed on the generic type parameterthey use at the class level. As with instance method, you can provide constraints for generic type parameters defined by the static method:
-
where T : IComparable<T>
-
perators in C# are nothing more than static methods and C# allows you to overload operators for your generic types.
-
Note that operators cannot define new generic type parameters.
-
static LinkedList<K,T> operator+(LinkedList<K,T> lhs, LinkedList<K,T> rhs)
-
A delegate defined in a class can take advantage of the generic type parameterof that class.
-
public delegate void GenericDelegate(T t)
-
C# 2.0 allows you to make a direct assignment of a method reference into a delegate variable:
-
delegates can define generic type parameters too:
-
Delegates defined outside the scope of a class can use generic type parameters. In that case, you have to provide the type arguments for the delegate when declaring and instantiating it:
-
And naturally, a delegate can define constraints to accompany its generic type parameters:
-
Generic delegates are especially useful when it comes to events. You can literally define a limited set of generic delegates, distinguished only by the number of the generic type parameters they require, and use these delegates for all of your event handling needs.
-
-
05 Mar 10
-
24 Feb 10
-
Generics allow you to define type-safe classes without compromising type safety, performance, or productivity. You implement the server only once as a generic server, while at the same time you can declare and use it with any type. To do that, use the < and > brackets, enclosing a generic type parameter. For example, here is how you define and use a generic stack:
-
-
27 Jan 10
-
24 Sep 08
-
use the where reserved keyword to define a constraint
-
As a result, the generic code could try to use methods, properties, or members of the generic type parameters that are incompatible with the specific type arguments the client uses
-
It is important to note that although constraints are optional, they are often essential when developing a generic type
-
generic interface IComparable<T>
-
derivation constraint
-
at most one base class can be used in a constraint
-
default constructor constraint
-
only define a constraint at the level where you require it
-
reference/value type constraint
-
cannot be a sealed class or a static class
-
appear after the actual derivation list
-
-
28 Aug 08
-
12 Aug 08
-
23 Jul 08
Would you like to comment?
Join Diigo for a free account, or sign in if you are already a member.