For a list of the invariant conditions for terms used in generic reflection, see the IsGenericType property remarks.
If a generic type is defined using C#, C++, or Visual Basic, then its nested types are all generic. This is true even if the nested types have no type parameters of their own, because all three languages include the type parameters of enclosing types in the type parameter lists of nested types. Consider the following classes:
Public Class Outermost(Of T)
Public Class Inner(Of U)
Public Class Innermost1(Of V)
End Class
Public Class Innermost2
End Class
End Class
End Class
public class Outermost<T>
{
public class Inner<U>
{
public class Innermost1<V> {}
public class Innermost2 {}
}
}
generic<typename T> public ref class Outermost
{
public:
generic<typename U> ref class Inner
{
public:
generic<typename V> ref class Innermost1 {};
ref class Innermost2 {};
};
};
The type parameter list of the nested class Inner has two type parameters, T and U, the first of which is the type parameter of its enclosing class. Similarly, the type parameter list of the nested class Innermost1 has three type parameters, T, U, and V, with T and U coming from its enclosing classes. The nested class Innermost2 has two type parameters, T and U, which come from its enclosing classes.
If the parameter list of the enclosing type has more than one type parameter, all the type parameters in order are included in the type parameter list of the nested type.
To construct a generic type from the generic type definition for a nested type, call the MakeGenericType method with the array formed by concatenating the type argument arrays of all the enclosing types, beginning with the outermost generic type, and ending with the type argument array of the nested type itself, if it has type parameters of its own. To create an instance of Innermost1, call the MakeGenericType method with an array containing three types, to be assigned to T, U, and V. To create an instance of Innermost2, call the MakeGenericType method with an array containing two types, to be assigned to T and U.
The languages propagate the type parameters of enclosing types in this fashion so you can use the type parameters of an enclosing type to define fields of nested types. Otherwise, the type parameters would not be in scope within the bodies of the nested types. It is possible to define nested types without propagating the type parameters of enclosing types, by emitting code in dynamic assemblies or by using the MSIL Assembler (Ilasm.exe). Consider the following code for the MSIL assembler:
.class public Outer<T> {
.class nested public Inner<U> {
.class nested public Innermost {
}
}
}
In this example, it is not possible to define a field of type T or U in class Innermost, because those type parameters are not in scope. The following assembler code defines nested classes that behave the way they would if defined in C++, Visual Basic, and C#:
.class public Outer<T> {
.class nested public Inner<T, U> {
.class nested public Innermost<T, U, V> {
}
}
}
You can use the MSIL Disassembler (Ildasm.exe) to examine nested classes defined in the high-level languages and observe this naming scheme.