简体   繁体   中英

typeof( ICollection<> ).GetTypeInfo().IsAssignableFrom( typeof(IList<>) )

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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM