这两行之间没有区别,因为第二行中的编译器理解它是 int 类型的数组。
var x = new int[] { 1, 2, 3 }; //Fine, x is int[]
var x = new [] { 1, 2, 3 }; //Fine, x is int[]
但为什么我不能用不同类型做到这一点?为什么编译器不能将我的变量转换为 object ?
var x = new object[] { 1, "df", 5 }; //Fine, x is object[]
var x = new [] { 1, "df", 5 }; //Error! "No best type found for implicity-typed-array"
修改
感谢您的所有答案。但我仍然想知道,使编译器无法转换为类型object
的所有表达式的优缺点是什么? (因为我使用var
表示法,这意味着它不能是任何类型。我这样理解。)为什么编译器不通过继承树找到最近类型的数组成员?
答案 0 :(得分:38)
new []
符号用于保存您键入数组成员的显式类型(或允许您创建其元素具有匿名类型的数组),但其类型推断受到限制,因为所有元素必须共享相同类型或可隐式转换为至少一个成员共享的公共类型。参见C#规范,第7.6.10.4节:
第三种形式的数组创建表达式称为隐式类型化数组创建表达式。它与第二种形式类似,不同之处在于未明确给出数组的元素类型,而是确定为数组初始值设定项中表达式集的最佳公共类型(第7.5.2.14节)。
以下是隐式类型化数组创建表达式的示例:
var a = new[] { 1, 10, 100, 1000 }; // int[] var b = new[] { 1, 1.5, 2, 2.5 }; // double[] var c = new[,] { { "hello", null }, { "world", "!" } }; // string[,] var d = new[] { 1, "one", 2, "two" }; // Error
最后一个表达式导致编译时错误,因为
int
和string
都不能隐式转换为另一个,因此没有最佳的常见类型。在这种情况下,必须使用显式类型化的数组创建表达式,例如,将类型指定为object[]
。或者,可以将其中一个元素强制转换为公共基类型,然后将其作为推断元素类型。
这里的关键点是“最常见类型”只能是已存在的类型之一。正如Damien_The_Unbeliever在评论中所指出的那样:“正如Lippert先生喜欢指出推理一样,无论什么时候它正在寻找最好的常见类型,它只会返回已经存在的类型之一 - 它不会寻找最衍生的共同祖先。“。
因为每个数组都可能是object []
并不意味着它应该。从编译器的角度来看,这是一个微不足道的最后选择,但对于开发人员而言,这是一个非常反直觉的选择,我猜。
答案 1 :(得分:18)
要扩展Joey的答案,请考虑以下示例:
interface IFoo { }
interface IBar { }
class A : IFoo, IBar { }
class B : IFoo, IBar { }
var array = new [] { new A(), new B() };
这两个类都实现了两个接口(也来自object
),那么应该为array
推断出哪种类型?
要回答您的评论,请考虑A
和B
仅共享一个界面的情况:
interface IFoo { }
class A : IFoo { }
class B : IFoo { }
var array = new [] { new A(), new B() };
A
和B
共享object
作为他们的基类,但是对于数组类型推断它是没有用的,也没用。如果有的话,人们会认为它是IFoo
,因此它会违反principle of least astonishment。但是,正如我已经说明的那样,这不可能一致地完成。
这里最安全,最一致的行为就是不允许类型推断。