Ask Learn
Preview
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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
{ ...
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign in