Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a generic type definition implemented interfaces lose type information?

For example, if you run the following code...

Type IListType = new List<string>().GetType()
                                   .GetInterface("IList`1")
                                   .GetGenericTypeDefinition();

...and you watch IListType variable, you'll find that the whole Type instance has all properties available like FullName and others.

But what happens when you run the code bellow?

Type IListType2 = typeof(List<>).GetInterface("IList`1")

Now IListType got from a generic type definition isn't the same as the first code sample: most Type properties will return null.

The main issue with this is that IListType == IListType2 doesn't equal while they're the same type.

What's going on?

This is ugly...

Now see what happens if you call IListType2.GetGenericTypeDefinition()... It recovers the type information!

It would be great that a .NET Framework development team member could explain us why an already generic type definition which has strangely lost its metadata has IsGenericTypeDefinition property set to false while it's still a generic type definition, and finally, if you call GetGenericTypeDefinition() on it, you recover the type information.

This is strange...

The following equality will be true:

Type IListType = new List<string>().GetType()
                        .GetInterface("IList`1")
                        .GetGenericTypeDefinition();

// Got interface is "like a generic type definition" since it has
// no type for T generic parameter, and once you call 
// GetGenericTypeDefinition() again, it recovers the lost metadata 
// and the resulting generic type definition equals the one got from
// List<string>!
Type IListType2 = typeof(List<>).GetInterface("IList`1").GetGenericTypeDefinition();

bool y = IListType == IListType2;
like image 762
Matías Fidemraizer Avatar asked Nov 18 '15 09:11

Matías Fidemraizer


People also ask

Can a generic class implement an interface?

Only generic classes can implement generic interfaces. Normal classes can't implement generic interfaces.

How is a generic interface defined?

A generic interface is primarily a normal interface like any other. It can be used to declare a variable but assigned the appropriate class. It can be returned from a method. It can be passed as argument.

Which interface defines methods to control the different generic collections?

NET class library defines several generic interfaces for use with the collection classes in the System. Collections. Generic namespace.

Which of the following syntax is used to declare a generic interface?

The general syntax to declare a generic interface is as follows: interface interface-name<T> { void method-name(T t); // public abstract method. } In the above syntax, <T> is called a generic type parameter that specifies any data type used in the interface.


2 Answers

The following types are all different and not connected by an inheritance relationship:

  • IList<T>
  • IList<int>
  • IList<string>

All of these have different Type objects because you can do different things with them. The latter two are the specializations of the former. The first is the generic type definition (which you can obtain through GetGenericTypeDefinition).

There is another part to the explanation. When you say class List<T> : IList<T> then the IList<T> part is not equal to typeof(IList<>) because it is already specialized to T. This is no longer a generic type definition. It is a concrete type such as IList<int>. It is specialized to bind its only type argument to the T that List<T> was specialized to.


Experiment for LINQPad:

Type bound = new List<string>().GetType().GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //string


Type bound = typeof(List<>).GetInterface("IList`1");
bound.GenericTypeArguments.Single().Dump(); //"T"
(bound.GenericTypeArguments.Single() == typeof(List<>).GetGenericArguments().Single()).Dump(); //true
like image 153
usr Avatar answered Oct 03 '22 00:10

usr


The first version of IList<T> is the actual typed version of IList<T>, let's say IList<string>.

The second one is the generic definition of IList<T> without a type for T.

That makes the two interfaces different. There are not the same, since the first is a concrete version of the second.

like image 25
Patrick Hofman Avatar answered Oct 03 '22 01:10

Patrick Hofman