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. In concept, generics are similar to C++ templates, but are drastically different in implementation and capabilities. This article discusses the problem space generics address, how they are implemented, the benefits of the programming model, and unique innovations, such as constrains, generic methods and delegates, and generic inheritance. You will also see how generics are utilized in other areas of the .NET Framework such as reflection, arrays, collections, serialization, and remoting, and how to improve on the basic offering.
What Are GenericsGenerics 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.
Generic ConstraintsWith 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.
It is important to note that although constraints are optional, they are often essential when developing a generic type. Without them, the compiler takes the more conservative, type-safe approach and only allows access to Object-level functionality in your generic type parameters. Constraints are part of the generic type metadata so that the client-side compiler can take advantage of them as well. The client-side compiler only allows the client developer to use types that comply with the constraints, thus enforcing type safety.