For a while now I’ve been wondering why C#’s support for covariance does not cover value types, both in normal array covariance and covariance in the generic parameter introduced in C# 4:
1: void Main()
3: int i = 0;
4: string str = "hello world";
6: TestMethod(i); // legal
7: TestMethod(str); // legal
8: TestMethod2(Enumerable.Empty<int>()); // illegal
9: TestMethod2(Enumerable.Empty<string>()); // legal
11: Console.WriteLine(i is object); // true
12: Console.WriteLine(new int is object); // false
13: Console.WriteLine(new string is object); // true
14: Console.WriteLine(new uint is int); // false
17: public void TestMethod(object obj)
22: public void TestMethod2(IEnumerable<object> objs)
Until I stumbled upon this old post by Eric Lippert on the topic of array covariance, which essentially points to a disagreement in the C# and CLI specification on the rule of array covariance:
"if X is assignment compatible with Y then X is assignment compatible with Y"
"if X is a reference type implicitly convertible to reference type Y then X is implicitly convertible to Y"
Whilst this doesn’t directly point to the generics case with IEnumerable<out T>, one would expect they are one and the same, otherwise you end up with different rules for int and IEnumerable<int> where (new int is IEnumerable<int>) == true.. now that would be weird!
Eric Lippert – Why is covariance of value-typed arrays inconsistent?
Question on StackOverflow – why does my C# array lose type sign information when cast to object?