|Important||This document may not represent best practices for current development, links to downloads and other resources may no longer be valid. Current recommended version can be found here.|
Generics in the Runtime (C# Programming Guide)
When a generic type or method is compiled into Microsoft intermediate language (MSIL), it contains metadata that identifies it as having type parameters. How the MSIL for a generic type is used differs based on whether or not the supplied type parameter is a value or reference type.
When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate places in the MSIL. Specialized generic types are created once for each unique value type used as a parameter.
For example, suppose your program code declared a stack constructed of integers, like this:
At this point, the runtime generates a specialized version of the
However, if at another point in your program code another Stack<T> class is created, this time with a different value type such as a long or a user-defined structure as its parameter, the runtime generates another version of the generic type, this time substituting a long in the appropriate places in MSIL. Conversions are no longer necessary because each specialized generic class natively contains the value type.
Generics work a little differently for reference types. The first time a generic type is constructed with any reference type, the runtime creates a specialized generic type with object references substituted for the parameters in the MSIL. Then, each time a constructed type is instantiated with a reference type as its parameter, regardless of what type it is, the runtime reuses the previously created specialized version of the generic type. This is possible because all references are the same size.
For example, suppose you had two reference types, a
Customer class and an
Order class, and further suppose that you created a stack of
At this point, the runtime generates a specialized version of the Stack<T> class that, instead of storing data, stores object references that will be filled in later. Suppose the next line of code creates a stack of another reference type, called
Unlike with value types, another specialized version of the Stack<T> class is not created for the
Order type. Rather, an instance of the specialized version of the Stack<T> class is created and the
orders variable is set to reference it. Suppose you then encountered a line of code to create a stack of a
As with the previous use of the Stack<T> class created with the
Order type, another instance of the specialized Stack<T> class is created, and the pointers contained therein are set to reference an area of memory the size of a
Customer type. Because the number of reference types can vary wildly from program to program, the C# implementation of generics greatly reduces code bloat by reducing to one the number of specialized classes created by the compiler for generic classes of reference types.
Moreover, when a generic C# class is instantiated with a type parameter, be it a value or reference type, it can be queried at runtime using reflection and both its actual type as well as its type parameter can be ascertained.