Partager via


Nested Types in Generic Classes

In C#, nested types can be defined in generic classes just like they would be in
non-generic classes. For example:

class G<T> {

  public class NestedC { }

  public enum NestedEnum { A, B }

}

Inside the nested type NestedC, we can still use type parameter T, which was "declared"
with class G<T>. Actually this is a misconception (the C# compiler does some
magic behind the scenes). If we were to use ildasm to view the node of NestedC,
we would find "NestedC" is a generic type with type parameter "T". As far as the
runtime is concerned, this "T" is not the same as the "T" with G<T>; they
just happen to have the same name.

.class private auto ansi beforefieldinit G`1<T>

  extends [mscorlib]System.Object

{

  .class auto ansi nested public beforefieldinit NestedC<T>

    extends [mscorlib]System.Object

  {   ...

When we use T inside NestedC, we are in fact referring to NestedC's own T, the type
parameter "T" declared with NestedC<T>. With that in mind, let us think about
what the following code will print:

class Test {

  static void Main() {

    Type type1 = typeof(G<int>.NestedC);

    Console.WriteLine(type1);

    Console.WriteLine(type1.IsGenericTypeDefinition);

 

    Type type2 = typeof(G<int>).GetNestedType("NestedC");

    Console.WriteLine(type2);

    Console.WriteLine(type2.IsGenericTypeDefinition);

  }

}

1. typeof(G<int>.NestedC) is translated by C# compiler to

  IL_0001:  ldtoken    class G`1/NestedC<int32>

  IL_0006:  call     class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype
[mscorlib]System.RuntimeTypeHandle)

The generic argument "int32" is bound to NestedC<>, not G<>;

2. You might already have noticed that although both are generic types, "NestedC"
does not have `(grave accent), but "G`1" does. So typeof(G<int>).GetNestedType("NestedC")
will get back the open generic type "NestedC<>".

Here is the result, is it as you expected?

   G`1+NestedC[System.Int32]

False

G`1+NestedC[T]

True

In summary, when written in C#, every type defined under a generic type will be
a generic type (including enum; C# does not allow us to explicitly define a generic
enum). To define a truly non-generic nested type inside a generic type, IL can help:

.class private auto ansi beforefieldinit G`1<T>

  extends [mscorlib]System.Object

{

  .class auto ansi nested public beforefieldinit NestedNonGenericC

    extends [mscorlib]System.Object

  {  ...

Comments

  • Anonymous
    February 17, 2006
       
           Type.FullName
           returns null when the type is not generic type definition but contains...