数组 object[] 的协变行为

3

我在将int[]赋值给object[]时遇到了编译错误(这个问题不是我提出的)。

接受的答案指出,这是由于数组协变性(为了更好地理解,请阅读问题和答案)。

现在我的情况是,虽然我无法将int[]赋值给object[],因为int是值类型(struct),但我想知道为什么现在可以这样做:

var arrayOfObjects = new object[] { 58, 58, 78 };// it accepts values types as initializers!

为什么如果我将值类型初始化到数组对象中,这会起作用?难道互换不应该接受值类型吗?

1
这被称为装箱int值被转换为对象类型。 - Icemanind
1
数组与协变无关。 - Yuval Itzchakov
1
我没有看到你在代码中使用协变。 - chomba
3个回答

7
因为您正在将一个项隐式地转换为 object。 您没有将 int [] 数组分配给 object []变量 - 您正在使用单个 int 值创建一个 object []变量(这些值会被隐式转换并装箱)。
为了不使用数组初始化程序来显示这一点:
object[] objarr = new object[1];
objarr[0] = 42; // Fine, translates basically into objarr[0] = (object)42;

int[] intarr = new int[1];
intarr[0] = 42; // Also fine

objarr = intarr; // No can do!

如果我使用十进制值(5.2)初始化数组,整个值是否会通过装箱保留?还是会改变(比如变成5)? - Misters
@misters 它将会被保留。'decimal' 将会被装箱,不会有任何隐式转换。 - Yuval Itzchakov

2

在这里,您不是在构建一个int[],整数被装箱到对象中,您正在构建一个object[]。您也可以将其他内容装箱:

var arrayOfObjects = new object[] { true, "false", 1, 10, new StringBuilder() }

1
为了从编译器的角度完成观点,考虑以下语句:
void Main()
{
    object[] or = new object[] { 1, 2 };
}

这是编译器生成的IL代码:

IL_0001:  ldc.i4.2    
IL_0002:  newarr      System.Object
IL_0007:  stloc.1     // System.Object[]
IL_0008:  ldloc.1     // System.Object[]
IL_0009:  ldc.i4.0    
IL_000A:  ldc.i4.1    
IL_000B:  box         System.Int32
IL_0010:  stelem.ref  
IL_0011:  ldloc.1     // System.Object[]
IL_0012:  ldc.i4.1    
IL_0013:  ldc.i4.2    
IL_0014:  box         System.Int32
IL_0019:  stelem.ref  
IL_001A:  ldloc.1     // System.Object[]
IL_001B:  stloc.0     // or
IL_001C:  ret      

编译器获取值,对值类型(int)执行box操作,然后调用stelem.ref,在一维数组中替换所提供索引处元素的值,用推送到堆栈上的ref (type O)值进行替换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接