Reputation: 371
I met with the strange behavior of the generic. Below is the code I use for testing.
public static class Program
{
public static void Main()
{
Type listClassType = typeof(List<int>).GetGenericTypeDefinition();
Type listInterfaceType = listClassType.GetInterfaces()[0];
Console.WriteLine(listClassType.GetGenericArguments()[0].DeclaringType);
Console.WriteLine(listInterfaceType.GetGenericArguments()[0].DeclaringType);
}
}
Output:
System.Collections.Generic.List`1[T]
System.Collections.Generic.List`1[T]
I found it very strange that the second Console.WriteLine call displays a class, not an interface, because I use a generic type definition. Is this correct behaviour?
I'm trying to implement generic type inference in my compiler. Suppose I have the code below.
public static class GenericClass
{
public static void GenericMethod<TMethodParam>(IList<TMethodParam> list) { }
}
And I want to call this method as follows:
GenericClass.GenericMethod(new List<int>());
In order to check the possibility of inference, I have to compare the type in the method signature, and type of arguments passed. But the code below returns false.
typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType;
Should I always use Type.GetGenericTypeDefinition for such comparisons?
Upvotes: 6
Views: 277
Reputation: 660004
Adding a second answer because you added a second question:
I'm trying to implement generic type inference in my compiler...
And thus I assume you're using reflection to build a compiler. This might not be a good idea. Reflection is much more performant now than it was back in the early days but it is still heavyweight compared to working directly with tokens. And reflection emit cannot emit every possible topology of types; it gets messed up in some scenarios involving nested struct types.
I would consider using CCI instead. We used a modified version of CCI for Roslyn.
the code below returns false.
typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType
That's correct. The parameter type is IList<TMethodParam>
and listInterfaceType
is IList<T>
where the T
is the generic parameter type declared by List<T>
, not the generic parameter type declared by IList<T>
. Those are all different types.
Should I always use Type.GetGenericTypeDefinition for such comparisons?
If you want to see if two generic types are both constructions of the same generic type, yes. If that's not what you want to check, then no.
This type system is complicated, so be very careful.
This is another reason to go with a token-based approach rather than a reflection-type-object based approach. When you have tokens in hand it is much easier to distinguish between a TypeDef
and a TypeRef
.
Upvotes: 2
Reputation: 660004
You're confusing two different types that are both named T. Think about it like this:
interface IFoo<TIFOO> { }
class Foo<TFOO> : IFoo<TFOO> {}
OK, what is the generic type definition of Foo<int>
? That's Foo<TFOO>
.
What is the interface implemented by Foo<TFOO>
? That's IFoo<TFOO>
.
What is the type argument of Foo<TFOO>
? Obviously TFOO
.
What type declared TFOO
? Foo<TFOO>
declared it.
What is the type argument of IFoo<TFOO>
? Obviously TFOO
, not TIFOO
.
What type declared TFOO
? Foo<TFOO>
declared it. not IFoo<TFOO>
. TFOO
comes from Foo
.
Make sense?
Upvotes: 15