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

末鹿安然 提交于 2019-12-11 07:49:18

问题


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.


回答1:


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.



回答2:


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


来源:https://stackoverflow.com/questions/18937119/typeof-icollection-gettypeinfo-isassignablefrom-typeofilist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!