C#中的数组在引用类型上隐式为协变的:
object[] listString = new string[] { "string1", "string2" }; 但不是值类型,因此如果更改string为int,则会得到编译错误:
object[] listInt = new int[] {0, 1}; // compile error 现在,您需要担心的是,当您int像以下两种语法那样声明数组时,它们下面没有显式声明类型int,仅区别于new[],编译器将以不同的方式处理:
object[] list1 = { 0, 1 }; //compile successfully object[] list2 = new[] {0, 1}; //compile error 您将object[] list1 = { 0, 1 };成功编译,但是object[] list2= new[] {0, 1};编译错误。
看来C#编译器对待
object[] list1 = { 0, 1 }; 如
object[] list1 = new object[]{ 0, 1 }; 但
object[] list2 = new[] { 0, 1 }; 如
object[] list2 = new int[]{ 0, 1 }; //error because of co-variant 在这种情况下,为什么C#编译器的行为方式不同? 问题来源于stack overflow
编译的版本使用数组初始化程序进行初始化list1。C#语言规范§1.110(“数组初始化器”)规定:
数组初始化程序由一系列变量初始化程序组成,这些变量初始化程序由“ {”和“}”标记包围,并由“,”标记分隔。每个变量初始化器都是一个表达式,对于多维数组,则是一个嵌套数组初始化器。
使用数组初始化程序的上下文确定要初始化的数组的类型。在数组创建表达式中,数组类型紧接在初始化器之前,或者从数组初始化器中的表达式推断出来。在字段或变量声明中,数组类型是要声明的字段或变量的类型。
在字段或变量声明中使用数组初始化程序时,例如:
int[] a = {0, 2, 4, 6, 8}; 它只是等效数组创建表达式的简写形式:
int[] a = new int[] {0, 2, 4, 6, 8}; 因此很明显,应该编译。
第二个版本使用显式的数组创建表达式,您可以在其中明确指示编译器创建哪种类型的数组。§1.51.10.4(“数组创建表达式”)规定:
第三种形式的数组创建表达式称为 隐式类型的数组创建表达式。它与第二种形式相似,不同之处在于未明确给出数组的元素类型,而是将其确定为数组初始值设定项中表达式集的最佳通用类型(第1.50.2.14节)。
因此,第二个版本相当于
object[] list2 = new int[] { 0, 1 }; 因此,问题实际上变成了“为什么我不能分配int[]一个object[]”,就像您在问题末尾提到的那样。答案也很简单,如第1.109节(“数组协方差”)所示:
数组协方差尤其不扩展到值类型数组。例如,不存在允许将an int[] 视为的转换object[]。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。