What is common rule to check if IEnumerable<T1>
covariant to IEnumerable<T2>
?
I've made some experiments:
1.
Object Obj = "Test string";
IEnumerable<Object> Objs = new String[100];
Works because IEnumerable<out T>
is covariant and String
inherits 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 reference type and MyStruct
is 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 inheritst ValueType
....
4.
MyInterface V3 = new MyStruct();
Console.WriteLine(V3 is MyInterface); // Output: "True"
IEnumerable<MyInterface> Vs3 = new MyStruct[100]; // Compilation error here
Even this way: "Cannot convert MyStruct to MyInterface". Oh, really?? You just did it one line before...
I've tried to formulate common rule:
public static bool IsCovariantIEnumerable(Type T1, Type T2 ){
return (T2.IsAssignableFrom(T1)) && !T2.IsValueType; // Is this correct??
}
So, questions is how to actually determine if IEnumerable<T1>
covariant to IEnumerable<T2>
? Is my IsCovariantIEnumerable(...)
function correct? If yes, is there any simplier way to check it? If not, how to fix it?
In your specific case it does not work because value types do not support co-variance.
But for the question how to determine if an IEnumerable<T2>
is co-variant to IEnumerable<T1>
:
The method Type.IsAssignableFrom()
tells you if an instance of a certain type is assignable to a variable of this type. So you can implement your method like that:
public static bool IsCovariantIEnumerable(Type T1, Type T2)
{
Type enumerable1 = typeof(IEnumerable<>).MakeGenericType(T1);
Type enumerable2 = typeof(IEnumerable<>).MakeGenericType(T2);
return enumerable1.IsAssignableFrom(enumerable2);
}
Usage:
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 stated above.
For completeness: Of course you don't need an extra method as you can easily do typeof(IEnumerable<object>).IsAssignableFrom(typeof(IEnumerable<string>)
.