为什么在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;