Concepts
A generic definition (IGenericDefinition) is a type or method that has generic parameters.
A specialization of a generic definition constructed by binding concrete arguments to formal generic parameters is called a generic instance (IGenericInstance).
Note that we have used the terms generic parameter (GenericParameterDeclaration) for formal parameters of generic definitions and generic argument, for generic instances, to mean the concrete types bound on formal parameters of generic instances.
Generic definitions and instances have no other common semantics than owning generic parameters and arguments, respectively.
The set of generic arguments bound to generic parameters in a given context is called the generic map (GenericMap) and each MSIL construction (instruction or metadata element) is said to have a generic context, i.e. a mapping of formal generic arguments to concrete generic parameters.
Generic parameters (or more precisely the generic argument to which they are bound at runtime) can be referred to in type signatures. This reference is implemented by the class. Semantics that are common to generic parameters and references to generic parameters are represented by the IGenericDefinition interface.
Example
Take the following C# example:
void SetValue<T>( T value )
{
this.value = value;
}
void Main()
{
SetValue<string>("Hello, world.");
}
The method SetValue<T>(T) is a generic
definition, but SetMethod<string>(string) is a
generic instance. The first occurrence of T (in
"<T>") is a generic parameter, the second one
(in "(T value)"), is a reference to the generic
parameter. The type string is the generic argument
bound to the generic parameter T.
Differences between PostSharp and System.Reflection
System.Reflection always resolves completely
generic parameters when you reflect a generic method instance to
its MethodBase or a generic type instance to its
Type.
For instance, if you reflect the
SetValue<string> generic method instance, you
will find that the type of the first parameter is
string. But this is a simplification and does not
correspond to CIL specifications! If you reflect the same generic
method instance using PostSharp, you will find that the type of the
first parameter is !!0, where !!0 is a
reference to the first method generic argument.
Generic Parameters
Generic parameters are belong to a generic method (MethodDefDeclaration) or a generic type (TypeDefDeclaration) and are represented by the GenericParameterDeclaration class. Generic parameters have a name, some attributes and optionally a set of constraints.
A constraint of a generic parameter is a class or an interface that the generic argument bound to this generic parameter is required to inherit or implement.
References to generic parameters are represented as instances of the GenericParameterTypeSignature class.
Semantics that are common to both generic parameters and references to generic parameters are specified in the IGenericParameter interface:
-
Generic parameters and arguments have an ordinal (i.e. a position).
-
Generic parameters and arguments are either of kind generic method parameter, either of kind generic type parameter.
-
It is possible to get a reference to a generic parameter.
More about Generic Context
The generic context of a generic declaration is a mapping between generic parameters and their associated content.
-
In case of generic definition, the context maps ordinals to generic parameters. The generic context of the
SetCollectionmethod is the map!!0→T, where is aGenericParameterDeclaration. -
In case of generic instance, the context maps ordinals to generic arguments. The generic context of the
SetCollection<int>method is the map!!0→int.
Now consider the following, more difficult construct:
class A
{
void Method<T1,T2>(T1 a, T2 b);
}
class B<T3>
{
void Method<T4>(T3 a, T4 b)
{ A.Method<T3,T4>(a, b); } }
class C {
void Method()
{
B<int>.Method<string>("Hello, world.");
}
}
We have the following contexts:
|
Construct |
Generic context |
|---|---|
|
A |
Empty |
|
A.Method |
!!0 → T1, !!1 → T2 |
|
B |
!0 → T3 |
|
B.Method |
!0 → T3, !!0 → T4 |
|
A.Method<T3,T4> |
!!0 → !0, !!1 → !!0 |
|
B<int>.Method<string>; |
!0 → int !!0 → string |