C# – 编译器错误 – 将int 赋给object

namespace ConsoleApplication1 { class Program { static void Main(string[] args) { object[] obj = new object[3]; obj[0] = new object(); obj[1] = "some string"; obj[2] = 10; string[] strings = new string[] { "one", "two", "three" }; obj = strings; //---> No Error here, Why ? int[] ints = new int[] { 1, 2, 3 }; obj = ints; /*-> Compiler error - Cannot implicitly convert type 'int[]' to 'object[]', Why ?*/ } } } 

如上所示,在执行该步骤时出现编译器错误。 但是,在上一步中,没有错误。 有人能解释一下这种行为吗? 我正在使用VS 2010。

编辑 – 为了完整性,再次,这将无法编译 – .NET 4.0中的差异支持现在已经清理。 可以generics类型参数中使用新关键字。

  List objectList = new List(); List stringList = new List(); objectList = stringList; 

只有引用类型的数组(如String )可以分配给其他引用类型的数组(如Object )。 由于int是值类型,因此可能无法将其数组分配给其他类型的数组。

更具体地说,这称为arrays协方差 。 它仅在存储在arrays中的位模式与目标类型兼容时才有效。 例如, String[]中的位都是对字符串的引用,可以安全地复制到存储对象引用的内存位置。 但是,值类型数组存储元素的实际数据(而不仅仅是对它们的引用)。 这意味着int[]将实际的32位整数存储在数组的元素中。 由于无法将32位整数安全地复制到存储对象或任何其他类型的引用的内存位置,因此无法将它们的数组分配给任何其他类型的数组。

请注意,从技术上讲, int的位可以安全地复制到存储uint的内存位置(反之亦然)。 这意味着您应该能够执行类似int[] x = new uint[10] 。 这实际上不是协方差,C#不允许它。 但是,它在CLR中是合法的,如果你愿意,你可以说服C#让你这样做。

stringobject都是引用类型。 也就是说,这些类型的变量实际上存储指向内存中其他位置的指针。 int是值类型。 也就是说,数据直接存储在声明变量的位置。

这意味着引用类型数组与值类型数组根本不同。 引用类型数组存储为指针数组。 因为指针的大小都相同,这意味着要将string[]重新解释为object[]意味着调整在访问数组中的项目时所做的类型检查(粗略地说)。

但是,在int[] ,值直接存储在数组中; int值连接在一起。 没有指针。 这意味着要将int[]重新解释为object[]需要将存储在数组中的每个值装入对象中。 因此,为什么你不能使用简单的强制转换或赋值 – 它是一个创建新数组的O(n)操作。 相反,您可以使用Array.Copy来处理所有拳击。

我看到的是一个引用类型数组可以分配另一个引用类型数组,而值类型数组则不能。 对我有意义

为什么这不起作用在这里的许多答案中说明,所以我不会尝试复制粘贴他们所说的内容。

如果您或其他人真的想这样做(将int[]转换为object[] )由于某种原因,您可以像这样使用LINQ:

 int[] ints = new int[] { 1, 2, 3 }; object[] obj_ints = (from i in ints select i).Cast().ToArray(); 

;)

如果您安装了Visual Studio,您将在VC#下的某处找到C#语言描述作为doc文件。 第12.5章涉及协方差,并说它

对于任何两个引用类型A和B,如果从A到B存在隐式引用转换(第6.1.6节)或显式引用转换(第6.2.4节),则数组类型A也存在相同的引用转换[ R]到数组类型B [R],其中R是任何给定的秩指定符(但两种数组类型都相同)。 这种关系称为arrays协方差。

这可能无法解答您的问题,但是在规范中这是故意做出的决定。