Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is typeof(Child<>).BaseType.IsGenericTypeDefinition false?

Tags:

c#

.net

generics

Example:

class Base<T>{}
class Child<T> : Base<T>{}

typeof( Base<> ).IsGenericTypeDefinition; // == true ie. parameterless 
typeof( Child<> ).BaseType.IsGenericTypeDefinition; // == false wtf???

// Eventually 
typeof( Base<> ) != typeof( Child<> ).BaseType;

Due to this feature typeof( Child<> ).IsSubclassOf( typeof( Base<> ) ) is not working.

like image 958
Denis535 Avatar asked Aug 05 '18 12:08

Denis535


2 Answers

I have read the documentation here and it explains the differences between IsGenericType and IsGenericTypeDefinition.

Your BaseType falls into this category: open constructed type

The ContainsGenericParameters property is true.

Examples are a generic type that has unassigned type parameters, a type that is nested in a generic type definition or in an open constructed type, or a generic type that has a type argument for which the ContainsGenericParameters property is true.

It is not possible to create an instance of an open constructed type.

So in order for a type definition to be generic you must be able to create an instance from it. But in this case, BaseType is an open constructed type and it is bound to it's inheritor: Child<T>, If you create a Child<int> then the base becomes Base<int>, not vice versa.

Therefore you can't create a generic type instance directly from the BaseType by calling MakeGenericType because it's type parameter is declared in the inheritor class Child<T>.

like image 97
Selman Genç Avatar answered Nov 15 '22 00:11

Selman Genç


I've found some information in the book Professional .NET 2.0 Generics, section Reflection and Generic Inheritance.

the inherited type is bound indirectly to the TValue parameter of the subclass.

I did some simple tests:

  var arg = typeof( Base<> ).GetGenericArguments()[ 0 ];
  Console.WriteLine( arg.DeclaringType ); // Base`1[T]

  arg = typeof( Child<> ).BaseType.GetGenericArguments()[ 0 ];
  Console.WriteLine( arg.DeclaringType ); // Child`1[T]

Term "parameterless" confused me. Actually even types with no specified generic parameters have parameters. It's types with arg.IsGenericParameter == true.

And these types can also be inherited. As in the usual case:

typeof( Child<int> ).BaseType == typeof( Base<int> );

The same way with parameterless case:

typeof( Base<> ) != typeof( Child<> ).BaseType; // it's something like: Base<T>.T !=  Child<T>.T
like image 41
Denis535 Avatar answered Nov 15 '22 01:11

Denis535