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?
See also these articles: 1, 2.
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>)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With