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?
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.
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;
Only generic classes can implement generic interfaces. Normal classes can't implement generic interfaces.
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.
NET class library defines several generic interfaces for use with the collection classes in the System. Collections. Generic namespace.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With