【问题标题】:Why doesn't the compiler convert var[] to object[] in c#?为什么编译器不将 var[] 转换为 c# 中的 object[]?
【发布时间】:2012-01-17 08:13:21
【问题描述】:

这两行没有区别,因为编译器在第二行就知道它是一个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表示法,这意味着它不能是任何类型。我是这样理解的。)为什么编译器不能通过继承树找到最近的数组成员类型?

【问题讨论】:

  • 是的,但问题主要是“为什么不以这种方式实现?”
  • Damien_The_Unbeliever 对乔伊的回答的评论说明了一切,真的。这对编译器来说工作量太大,更不用说推断object[],结果对我来说非常违反直觉。
  • 这可能是因为语言设计者认为对象数组很臭,他们不希望 C# 使用起来很容易,用起来很臭。
  • 仅供参考,var 关键字与您的问题无关。 object[] x = new[] { 1, "df" }; 也不起作用。

标签: c# .net c#-4.0 object new-operator


【解决方案1】:

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

最后一个表达式导致编译时错误,因为intstring 都不能隐式转换为另一个,因此没有最佳通用类型。在这种情况下,必须使用显式类型的数组创建表达式,例如将类型指定为object[]。或者,可以将其中一个元素强制转换为通用的基本类型,然后该基本类型将成为推断的元素类型。

这里的关键点是“最佳通用类型”只能是已经存在的类型之一。正如Damien_The_Unbeliever 在评论中指出的那样:“正如 Lippert 先生喜欢指出的推理,每当它寻找最佳通用类型时,它只会返回已经存在的类型之一 - 它不会不要去寻找最衍生的共同祖先。”.

仅仅因为每个数组都可以是object [] 并不意味着它应该。从编译器的角度来看,这将是一个微不足道的最后选择,但对于开发人员来说,这是一个非常违反直觉的选择。

【讨论】:

  • 为什么没有实现 new[] 来提供这样的转换呢?这样做有什么坏处?
  • 不,new[] 表示法主要用于方便匿名类型的数组。节省打字只是一个很好的副作用。
  • why 可能是 Eric Lippert 能够回答的问题。我对历史有点模糊,但完整的类型推断来自var,也许new [] 早于此。
  • new Object() 添加到数组中,它编译得很好。正如 Lippert 先生喜欢在推理时指出的那样,每当它寻找最佳常见类型时,它只会返回已经存在的类型之一 - 它不会寻找最衍生的共同祖先。跨度>
  • 达米恩,谢谢。我补充说。老实说,如果您直接深入了解规范的这一部分,就很难理解。
【解决方案2】:

要扩展 Joey 的答案,请考虑以下示例:

interface IFoo { }
interface IBar { }

class A : IFoo, IBar { }
class B : IFoo, IBar { }

var array = new [] { new A(), new B() };

两个类都实现了这两个接口(并且还派生自object),那么应该为array 推断出哪种类型?


要回答您的评论,请考虑AB 仅共享一个接口的情况:

interface IFoo { }

class A : IFoo { }
class B : IFoo { }

var array = new [] { new A(), new B() };

AB 都共享 object 作为它们的基类,但是为数组类型推断这一点是没有帮助的,而且大多是无用的。如果有的话,人们会认为它是IFoo,所以它会违反principle of least astonishment。但是,正如我已经说明的那样,这不能始终如一地完成。

这里最安全和最一致的行为就是不允许类型推断。

【讨论】:

  • +1。我们总是倾向于忘记 .NET确实支持多重继承(尽管仅通过接口)。
  • 是的,很好的例子。但是为什么在这个例子中他不能转换为对象。他可以找到最接近的类型,它们都是继承的。没有多重继承,所以他可以通过树的单个分支搜索......
  • @mesiesta:他们可能只有一个共同的基础class,但为什么要优先于他们实现的接口呢?接口也是类型。
  • 是的,我知道...我的意思是根本不看接口...只看基类(只能有一个)。
  • 但是为什么基类比接口更重要呢?查看我的更新:有时接口比基类更重要。
猜你喜欢
  • 1970-01-01
  • 2017-10-12
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 1970-01-01
相关资源
最近更新 更多