c# -编译错误-将int[]赋值给对象[]时
本文关键字:赋值 对象 int 编译 错误 | 更新日期: 2023-09-27 18:07:36
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中的方差支持现在已经清理了。可以使用新的关键字in和out与泛型类型参数。
List<object> objectList = new List<object>();
List<string> stringList = new List<string>();
objectList = stringList;
只有引用类型的数组(如String
)可以赋值给其他引用类型的数组(如Object
)。由于int
是值类型,它的数组不能赋值给其他类型的数组
更具体地说,这被称为数组协方差。只有当存储在数组中的位模式与目标类型兼容时,它才有效。例如,String[]
中的位都是对字符串的引用,可以安全地复制到存储对象引用的内存位置。然而,值类型数组存储元素的实际数据(而不仅仅是对它们的引用)。这意味着int[]
将实际的32位整数存储在数组的元素中。由于32位整数不能安全地复制到存储对象引用或任何其他类型的内存位置,因此不能将32位整数的数组赋值给任何其他类型的数组。
注意,从技术上讲,int
的位可以安全地复制到存储uint
的内存位置(反之亦然)。这意味着您应该能够执行int[] x = new uint[10]
之类的操作。这实际上不是协方差,c#也不允许。然而,它在CLR中是合法的,如果你想的话,你可以说服c#允许你这样做。
string
和object
都是引用类型。也就是说,这些类型的变量实际上在内存中存储了一个指向其他地方的指针。int
是一个值类型。也就是说,数据直接存储在声明变量的地方。
这意味着引用类型数组与值类型数组在本质上是不同的。引用类型数组存储为指针数组。因为指针的大小都是相同的,这意味着将string[]
重新解释为object[]
只意味着在访问数组中的项时(粗略地说)调整类型检查。
然而,在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<object>().ToArray();
。
我看到的是引用类型的数组可以被赋值给另一个引用类型的数组,而值类型的数组却不能。Make sense to me
如果你安装了Visual Studio,你会发现c#语言规范作为文档文件在vc#下的某个地方。第12.5章讨论协方差,这里写着
对于任意两个引用类型A和B,如果是隐式引用存在转换(§6.1.6)或显式引用转换(§6.2.4)从A到B,那么同样的引用转换也存在数组类型A[R]到数组类型B[R],其中R是任意给定的等级说明符(但两种数组类型相同)。这种关系称为数组协方差
这可能不能回答你的问题,但这是规范中深思熟虑的决定。