How to check if `IEnumerable <T1>` is covariant for `IEnumerable <T2>`?
What is the general rule to check if IEnumerable<T1> covariant to IEnumerable<T2> ?
I did some experiments:
one.
Object Obj = "Test string"; IEnumerable<Object> Objs = new String[100]; This works because IEnumerable<out T> is covariant, and String inherits from Object .
2.
interface MyInterface{} struct MyStruct:MyInterface{} ..... Object V = new MyStruct(); Console.WriteLine(new MyStruct() is Object); // Output: True. IEnumerable<Object> Vs = new MyStruct[100]; // Compilation error here MyStruct is actually an Object , but it does not work, because Object is a reference type and MyStruct is a value type. Ok, I see some logic here.
3.
Console.WriteLine(new MyStruct() is ValueType); // Output: "True" ValueType V2 = new MyStruct(); IEnumerable<ValueType> Vs2 = new MyStruct[100]; // Compilation error here Should work, because IEnumerable<out T> is covariant and MyStruct IS ValueType , but does not work ... OK, maybe MyStruct does not actually inherit ValueType ....
4.
MyInterface V3 = new MyStruct(); Console.WriteLine(V3 is MyInterface); // Output: "True" IEnumerable<MyInterface> Vs3 = new MyStruct[100]; // Compilation error here Even so: "Unable to convert MyStruct to MyInterface." Oh really?? You just did this one line earlier ...
I tried to formulate a general rule:
public static bool IsCovariantIEnumerable(Type T1, Type T2 ){ return (T2.IsAssignableFrom(T1)) && !T2.IsValueType; // Is this correct?? } So the questions are, how to determine if IEnumerable<T1> covariant to IEnumerable<T2> ? Is my IsCovariantIEnumerable(...) function correct? If so, is there an easier way to verify this? If not, how to fix it?
In your particular case, this does not work, because value types do not support covariance.
But to the question, how to determine if IEnumerable<T2> co-option to IEnumerable<T1> :
The Type.IsAssignableFrom() method reports whether Type.IsAssignableFrom() can be an instance of a specific type of a variable of this type. So you can implement your method like this:
public static bool IsCovariantIEnumerable(Type T1, Type T2) { Type enumerable1 = typeof(IEnumerable<>).MakeGenericType(T1); Type enumerable2 = typeof(IEnumerable<>).MakeGenericType(T2); return enumerable1.IsAssignableFrom(enumerable2); } Using:
if (IsCovariantIEnumerable(typeof(object), typeof(string)) Console.WriteLine("IEnumerable<string> can be assigned to IEnumerable<object>"); But IsCovariantIEnumerable(typeof(object), typeof(MyStruct)) will return false for the reason mentioned above.
For completeness: Of course, you do not need an additional method, since you can easily make typeof(IEnumerable<object>).IsAssignableFrom(typeof(IEnumerable<string>) .