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;
答案 0 :(得分:6)
只有引用类型数组(如String
)可以分配给其他引用类型的数组(如Object
)。由于int
是值类型,因此可能无法将其数组分配给其他类型的数组。
更具体地说,这称为array covariance。它仅在存储在阵列中的位模式与目标类型兼容时才有效。例如,String[]
中的位都是对字符串的引用,可以安全地复制到存储对象引用的内存位置。但是,值类型数组存储元素的实际数据(而不是仅仅引用它们)。这意味着int[]
将实际的32位整数存储在数组的元素中。由于无法将32位整数安全地复制到存储对象或任何其他类型的引用的内存位置,因此无法将它们的数组分配给任何其他类型的数组。
请注意,从技术上讲,int
的位可以安全地复制到存储uint
的内存位置(反之亦然)。这意味着您应该能够执行int[] x = new uint[10]
之类的操作。这实际上不是协方差,C#不允许它。但是,它在CLR中是合法的,你可以说服C#让你这样做。
答案 1 :(得分:2)
string
和object
都是引用类型。也就是说,这些类型的变量实际上存储了指向内存中其他位置的指针。 int
是值类型。也就是说,数据直接存储在声明变量的位置。
这意味着引用类型数组与值类型数组根本不同。引用类型数组存储为指针数组。因为指针的大小都相同,这意味着将string[]
重新解释为object[]
simpy意味着在访问数组中的项时调整类型检查(粗略地说)。
但是,在int[]
中,值直接存储在数组中; int值连接在一起。没有指针。这意味着要将int[]
重新解释为object[]
,需要将存储在数组中的每个值装入对象中。因此,为什么你不能使用简单的强制转换或赋值来实现它 - 这是一个创建新数组的O(n)操作。相反,您可以使用Array.Copy
来处理所有拳击。
答案 2 :(得分:1)
我看到的是一个引用类型数组可以分配另一个引用类型数组,而值类型数组则不能。对我有意义
答案 3 :(得分:1)
为什么这不起作用在这里的许多答案中说明,所以我不会尝试复制粘贴他们说的话。
如果您或其他人真的想这样做(将int[]
转换为object[]
)由于某种原因,您可以像这样使用LINQ:
int[] ints = new int[] { 1, 2, 3 };
object[] obj_ints = (from i in ints select i).Cast<object>().ToArray();
)
答案 4 :(得分:0)
如果您安装了Visual Studio,您将在VC#下的某处找到C#语言描述作为doc文件。第12.5章涉及协方差,并在那里说
对于任何两个引用类型A和B,如果是隐式引用 存在转换(第6.1.6节)或显式引用转换(第6.2.4节) 从A到B,然后也存在相同的参考转换 数组类型A [R]到数组类型B [R],其中R是任何给定的 rank-specifier(但两种数组类型都相同)。这种关系 被称为阵列协方差。
这可能无法解答您的问题,但在规范中这是故意做出的决定。