Reputation: 4548
I am trying to check the following
typeof( ICollection<> ).GetTypeInfo().IsAssignableFrom( targetProperty.PropertyType.GetTypeInfo() )
where the argument passed into IsAssignableFrom
is an IList<Something>
. But it is returning false.
The following also returns false.
typeof( ICollection<> ).GetTypeInfo().IsAssignableFrom( targetProperty.PropertyType.GetTypeInfo().GetGenericTypeDefinition() )
Even the following is returning false.
typeof( ICollection<> ).GetTypeInfo().IsAssignableFrom( typeof(IList<>) )
Shouldn't the latter definitely return true?
How can I get the correct result when targetProperty.PropertyType
can be any type at all? It could be a List<T>
, an ObservableCollection<T>
, a ReadOnlyCollection<T>
, a custom collection type, etc.
Upvotes: 2
Views: 3667
Reputation: 40818
You have two open generic types. IsAssignableFrom
interprets these like asking whether ICollection<T1>
is assignable from IList<T2>
. This is, in general, false. It is only true when T1 = T2. You need to do something to close the generic types with the same type argument. You could fill in the type as object
or you could get the generic parameter type and use that:
var genericT = typeof(ICollection<>).GetGenericArguments()[0]; // a generic type parameter, T.
bool result = typeof(ICollection<>).MakeGenericType(genericT).IsAssignableFrom(typeof(IList<>).MakeGenericType(genericT)); // willl be true.
It seems GetGenericArguments
is not available in PCL, and its behavior is different than GenericTypeArguments
property. In a PCL you need to use GenericTypeParameters
:
var genericT = typeof(ICollection<>).GetTypeInfo().GenericTypeParameters[0]; // a generic type parameter, T.
bool result = typeof(ICollection<>).MakeGenericType(genericT).GetTypeInfo().IsAssignableFrom(typeof(IList<>).MakeGenericType(genericT).GetTypeInfo()); // willl be true.
Upvotes: 5
Reputation: 54887
ICollection<T1>
cannot be assigned from IList<T2>
in general; otherwise, you could end up with situations where you assign, say, a List<char>
to an ICollection<bool>
.
typeof(ICollection<>).IsAssignableFrom(typeof(IList<>)) // false
typeof(ICollection<bool>).IsAssignableFrom(typeof(List<int>)) // false
You can, however, assign ICollection<T>
from IList<T>
, provided that the type parameter T
is the same.
typeof(ICollection<bool>).IsAssignableFrom(typeof(List<bool>)) // true
Starting from C# 4, this also works for type covariance:
typeof(IEnumerable<BaseClass>).IsAssignableFrom(typeof(List<DerivedClass>)));
// true in C# 4
// false in prior verions
Similarly, you can assign non-generic base interfaces from any generic type that implements them:
typeof(ICollection).IsAssignableFrom(typeof(List<bool>)) // true
Upvotes: 1