以下代码无法编译:
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”标签,因为这个问题没有涉及拳击。
答案 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;