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

时间:2008-10-14 18:29:30

标签: c# nullable conditional-operator dbnull

以下代码无法编译:

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

我得到:错误1无法确定条件表达式的类型,因为'System.DBNull'和'string'之间没有隐式转换

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

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

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

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

在我看来,当三元分支的类型不同时,编译器不会将值自动提供给类型对象...但是当它们属于同一类型时,则自动装箱是自动的。

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

有人能描述为什么编译器不允许这样做以及为什么C#的设计者选择这样做?我相信这在Java中是合法的......虽然我还没有证实这一点。

感谢。

编辑:我要求理解为什么Java和C#以不同的方式处理这个问题,C#中幕后发生的事情使这个问题无效。我知道如何使用三元,而不是寻找一个“更好的方法”来编写示例代码。我理解C#中的三元规则,但我想知道为什么......

编辑(Jon Skeet):删除了“autoboxing”标签,因为这个问题没有涉及拳击。

3 个答案:

答案 0 :(得分:68)

编译器要求第二个和第三个操作数的类型相同,或者一个可以隐式转换为另一个。在您的情况下,类型是DBNull和字符串,它们都不能隐式转换为另一个。将它们中的任何一个投射到对象上就可以解决这个问题。

编辑:看起来它在Java中确实合法。当谈到方法重载时,它是如何工作的,我不确定......我刚刚看了JLS,当有两个不兼容的引用时,条件的类型是什么的非常不清楚涉及的类型。 C#工作方式偶尔可能会更加刺激,但IMO更清晰。

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

  

第二和第三个操作数   ?:操作员控制的类型   条件表达式。设X和Y为   第二和第三类型   操作数。然后,

     
      
  • 如果X和Y是相同类型,则这是条件
  • 的类型   
  • 否则,如果从X到Y存在隐式转换(第6.1节),   但不是从Y到X,那么Y就是   条件表达式的类型。
  •   
  • 否则,如果从Y到X存在隐式转换(第6.1节),   但不是从X到Y,那么X就是   条件表达式的类型。
  •   
  • 否则,无法确定表达式类型和编译时间   发生错误。
  •   

答案 1 :(得分:18)

DBNull.Value会返回DBNull类型。

您希望类型为string

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

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

基本上如果您使用:

[condition] ? true value : false value;

在.Net中,无论你将它们分配给它们,都需要将true和false选项隐式转换为相同的类型。

这是C#处理类型安全的结果。例如,以下内容有效:

string item = "item";

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

C#3不支持动态类型,那么什么是测试?在C#中,每个赋值也是一个带有返回值的语句,因此尽管var结构在C#3中是新的,但是equals右边的语句总是必须解析为单个类型。

在C#4及更高版本中,您可以明确支持动态类型,但我认为这不会有帮助。

答案 2 :(得分:10)

顺便说一句,您的代码是一个特殊情况,根本不必使用条件运算符。相反,null coalesce运算符更合适(但仍需要转换):

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