bool IsTypeAGenericList(Type listType)
{
typeof(IList<>).IsAssignableFrom(listType.GetGenericTypeDefinition())
}
returns false when given typeof(List<int>)
.
I assume this is because the two type parameters can be different, correct?
bool IsTypeAGenericList(Type listType)
{
typeof(IList<>).IsAssignableFrom(listType.GetGenericTypeDefinition())
}
returns false when given typeof(List<int>)
.
I assume this is because the two type parameters can be different, correct?
I guess the method doesn't really make sense, because an instance is never of the generic type - it's always constructed with a particular type argument.
In other words, you could never have an "open" variable to assign into, nor a reference to an open instance to use as the value for the assignment.
As you say, you don't know whether the type parameters will be the same - so (for instance) you could define:
class BizarreList<T> : IList<int>
It feels like there should be some way of expressing the relationship though...
Actually, this works:
public static bool IsGenericList(Type type)
{
if (!type.IsGenericType)
return false;
var genericArguments = type.GetGenericArguments();
if (genericArguments.Length != 1)
return false;
var listType = typeof (IList<>).MakeGenericType(genericArguments);
return listType.IsAssignableFrom(type);
}
This really has to do with open constructed types.
When you say:
class List<T> : IList<T>
You're actually saying: my class is called List, it has one type parameter called T, and it implements the interface that is constructed from IList<> using the same T. So the T in the definition part and the T in the "implements" part both refer to the same type parameter -- you declare it before the colon, then you immediately reference it after the colon.
It gets confusing because IList<>
's type parameter is also called T -- but that is a different type parameter entirely. So let's re-declare our concrete class like this:
class List<U> : IList<U>
This is completely equivalent to the above, only now we can say "U" when we refer to the type parameter of List, and T when we refer to the one from IList. They're different types.
Now it gets easier to see why the generic type definition List<U>
(which is what you mean when you say typeof(List<>)
) does not implement the generifc type definition IList<T>
(which is what you mean when you say typeof(IList<>)
), but rather it implements the open generic constructed type IList<U>
(that is, IList constructed with List's own type paremeter).
So basically, generic type definitions never inherit or implement other generic type definitions -- they usually implement open constructed types using their own type parameters with other generic type definitions.
Ripper234's answer shows how to handle this particular case using Reflection, so I won't repeat it; I just wanted to clarify the relationship between those types, and I hope it came out at least somewhat intelligible.