Casting int[] to object[]

2019-01-28 11:45发布

问题:

I encountered with question: why it's impossible cast int[] to object[] , e.g. object[] o = new int[] { 0, 1, 2 };

Meanwhile I can cast to just object and back to int[].

I'll be glad to hear deep answer.

回答1:

Directly from the docs:

Array covariance specifically does not extend to arrays of value-types. For example, no conversion exists that permits an int[] to be treated as an object[].

An array of ints or any other value-type is not an array of objects. Value types have different storage characteristics to those of reference types. An array of (reference type) objects holds a list of object references (with the objects themselves living in the heap), so the slots will always be a constant width. Value types, on the other hand, store their value directly in the array, so the slots might be any width. This makes a conversion between the two meaningless.

It's a little confusing because even though value-types are derived from System.Object, they behave very differently to reference types, and object-like behaviour of value types (e.g. boxing) is only possible through magical handling of them by the compiler and runtime, and it doesn't extend to arrays.

As a side note, casting arrays is a well dodgy practice. I wouldn't do it.



回答2:

For an instance of type A to be castable to type B, one of the following conditions must be true:

  1. there is an implicit/explicit conversion from A to B;
  2. there is a hierarchical relationship. Such a relationship could be achieve through one of two ways:
    1. deriving A from B (e.g., class A : B {})
    2. covariance/contravariance. C# allows covariance for:
      1. arrays of reference types (string[] > object[]) (*)
      2. generic types arguments in interfaces/delegates (IEnumerable<string> > IEnumerable<object> and Func<string> > Func<object>)
      3. delegates ( string Method() {} can be assigned to delegate object Del(); )

You cannot cast int[] to object[] because none of the above conditions are true.


(*) - You should avoid this though - array covariance is broken and was it was added simply so that the CLR would support Java-like languages.



回答3:

Although type System.Int32 derives from object, and references to System.Int32 object instances can be used as references to System.Object, an array of type System.Int32[] does not hold instances of System.Int32, nor does it hold references to them. Instead, each element of an array will hold just the 32-bit numeric value associated with an Int32, without holding any of the other information associated with an object instance. Although C# will allow code like:

Object[] array = new Object[3];
int five = 5;
array[0] = five;
array[1] = five;
array[2] = array[0];

the code isn't storing five, nor a reference to it, into the array. Instead, the assignment to array[0] will create a new object of type System.Int32 which holds the number 5 and store a reference to that. The assignment to array[1] will then create another new object of type System.Int32, which also holds the value 5, and store a reference to that. The third assignment will store into array[2] a reference to the same object as array[0]. Note that even though all three array slots seem to hold the number 5, they actually hold more information than that. The array also encapsulates the fact that array[0] and array[2] hold references to one object, while array[1] holds a reference to another.

When a reference type is cast to its parent type, the resulting reference is required to identify the same object as the original. Consequently, the object identified by the resulting reference cannot encapsulate any more information than the object identified by the original (it's the same object, after all!). Because an Object[], even one whose elements all identify instances of System.Int32, encapsulates information beyond what can be stored in an int[], it is not possible for an int[] and an Object[] to be one and the same object.



标签: c# clr