Why is an array of ints not an array of objects? And why can a pattern of type 'object[]' not be used for 'int[]'?
1 is object
True
new int[10] is object
True
new int[10] is object[] // Why?
False
(Array)new int[10] is object[]
False
(Array)new object[10] is object[]
True
new object() is object
True
new object[10] is object
True
new object[10] is object[]
True
int[] arr = new int[10];
// Why the compilation error?
// error CS8121: An expression of type 'int[]' cannot be handled by a pattern of type 'object[]'
if (arr is object[] objArr)
Console.WriteLine(objArr);
// And this works:
if ((Array)arr is object[] objArr)
Console.WriteLine(objArr);
I came across this line in the source code: https://source.dot.net/#System.Private.CoreLib/Array.cs,1644
.NET version is 3.1.10 (same on mono 6.4.0).
Actually (if I understand the problem correctly), in this case, it's because value types are not covariant:
(Array)new string[10] is object[]
true
(Array)new int[10] is object[]
false
The CLR disallows it because it needs to preserve the identity, where as boxing will not, it fundamentally changes the type in memory
Eric Lippert has a great blog post about identity at Representation and identity:
covariant and contravariant conversions of interface and delegate types require that all varying type arguments be of reference types. To ensure that a variant reference conversion is always identity-preserving, all of the conversions involving type arguments must also be identity-preserving. The easiest way to ensure that all the non-trivial conversions on type arguments are identity-preserving is to restrict them to be reference conversions.
Let´s make an example that contains lists instead of arrays, because the same semantics apply.
Assume you have a list of base-class Animal
. If you could cast List<Giraffe>
to List<Animal>
, you can do this also:
((List<Animal> myGiraffes).Add(new Lion())
which surely breaks your concept of type-safety. That´s why List<T>
is not co-variant. In your case you have an array, which - by error or design - however is co-variant. Thus you can convert an array of any type to an array of type object
.
object[] a = new string[0];
Also have a look at Why are arrays covariant but generics are invariant?. In short arrays exist far longer in the language-concepts of C# then generics and co-variance.
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