Why is the base type of an open generic type not open?

Consider a piece of the code below:

public class A<T> { }

public class B<T> : A<T> { }

In such case:

var a = typeof(A<>).GenericTypeArguments.Length;

a has the value 0, which is not surprising. This, however, is somehow unexpected for me:

var b = typeof(B<>).BaseType.GenericTypeArguments.Length;

where b has the value 1. So it is closed using a non-existing type of name "T" and only doing GetGenericTypeDefinition on it makes it open again. Why is that?

Jon Skeet
people
quotationmark

So it is closed using a non-existing type of name "T" and only doing GetGenericTypeArgument on it makes it open again. Why is that?

Because there is one type argument provided - the type parameter to B.

Look at how you're specifying the base class:

public class B<T> : A<T>

What's the T in A<T> if it's not a type argument? Just because the type argument is itself a type parameter doesn't mean it's not being specified as a type argument.

Consider this:

public class A<T1, T2> { }

public class B<T> : A<T, int> { }

Here, the base class of B<T> is A<T, int> - and you can determine that the int has been specified by asking for the type arguments. You can also show where the T comes from:

using System;
using System.Reflection;
using System.Collections.Generic;

public class A<T1, T2> { }

public class B<T> : A<T, int> { }

class Program
{
    static void Main()
    {
        var bT = typeof(B<>).GetTypeInfo().GenericTypeParameters[0];
        var listT = typeof(List<>).GetTypeInfo().GenericTypeParameters[0];
        var bBaseArguments = typeof(B<>).BaseType.GenericTypeArguments;
        Console.WriteLine(bBaseArguments[0] == bT); // True
        // Shows that the T from B<T> isn't the same as the T from List<T>
        Console.WriteLine(bBaseArguments[0] == listT); // False
        Console.WriteLine(bBaseArguments[1] == typeof(int)); // True
    }
}

people

See more on this question at Stackoverflow