为什么在C#中这个代码无效?

下面的代码将不能编译:

string foo = "bar"; Object o = foo == null ? DBNull.Value : foo; 

我得到: 错误1条件expression式的types无法确定,因为没有“System.DBNull”和“string”之间的隐式转换

要解决这个问题,我必须做这样的事情:

 string foo = "bar"; Object o = foo == null ? DBNull.Value : (Object)foo; 

这个演员似乎毫无意义,因为这当然是合法的:

 string foo = "bar"; Object o = foo == null ? "gork" : foo; 

在我看来,当三元分支是不同types的时候,编译器不会自动把值赋给types对象…但是当它们是同一types时,自动装箱是自动的。

在我看来,第一个陈述应该是合法的…

任何人都可以描述为什么编译器不允许这样做,为什么C#的devise者select这样做? 我相信这是合法的Java …虽然我没有证实这一点。

谢谢。

编辑:我要求了解为什么Java和C#处理这个不同的是,在C#中,这使得这个无效的场景下发生了什么。 我知道如何使用三元组,而不是寻找“更好的方法”来编写例子。 我理解C#中的三元规则,但我想知道为什么…

编辑 (乔恩Skeet):删除“自动装箱”的标签,因为没有拳击参与这个问题。

编译器要求第二个和第三个操作数的types是相同的,或者一个隐式地转换到另一个。 在你的情况下,types是DBNull和string,两者都不能隐式转换到另一个。 将其中的任何一个投射到物体上解决了这个问题。

编辑:看起来像是在Java确实是合法的。 不知道怎么办,当涉及到方法重载时,我不知道…我只是看了JLS,当有两个不兼容的引用的时候,条件的types是什么,这是非常不清楚的涉及的types。 C#的工作方式偶尔会更加刺激,但是更清晰的是IMO。

C#3.0规范的相关部分是7.13,条件运算符:

?:操作符的第二个和第三个操作数控制条件expression式的types。 设X和Y是第二个和第三个操作数的types。 然后,

  • 如果X和Y是相同的types,那么这是条件types
  • 否则,如果存在从X到Y而不是从Y到X的隐式转换(第6.1节),则Y是条件expression式的types。
  • 否则,如果存在从Y到X而不是从X到Y的隐式转换(第6.1节),则X是条件expression式的types。
  • 否则,不能确定expression式types,并发生编译时错误。

DBNull.Value返回typesDBNull

你想要的types是string

虽然string可以是null但不能是DBNull

在你的代码中,等号右边的语句在赋值给对象之前执行。

基本上如果你使用:

 [condition] ? true value : false value; 

在.Net中,true和false选项都需要隐式转换为相同的types,然后再分配给它们。

这是C#如何处理types安全的结果。 例如以下是有效的:

 string item = "item"; var test = item != null ? item : "BLANK"; 

C#3不支持dynamictypes,那么testing是什么? 在C#中,每个赋值也是一个带有返回值的语句,所以虽然在C#3中var结构是新的,但是等号右边的语句总是必须parsing为单个types。

在C#4及以上版本中,您可以明确地支持dynamictypes,但我认为这不会有帮助。

顺便说一句,你的代码是一个特殊的情况,根本不需要使用条件运算符。 相反,空合并操作符更合适(但仍需要强制转换):

 object result = (object)foo ?? DBNull.Value;