使用条件/三元(“?:”)运算符进行转换
我有以下 C# 源代码摘录:
object valueFromDatabase;
decimal result;
valueFromDatabase = DBNull.Value;
result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0);
result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
第一个结果评估抛出 InvalidCastException
,而第二个结果评估则不会。 这两者有什么区别?
I have this extract of C# source code:
object valueFromDatabase;
decimal result;
valueFromDatabase = DBNull.Value;
result = (decimal)(valueFromDatabase != DBNull.Value ? valueFromDatabase : 0);
result = (valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
The first result evaluation throws an InvalidCastException
whereas the second one does not.
What is the difference between these two?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
更新:这个问题是我 2010 年 5 月 27 日博客的主题。 感谢您提出的好问题!
这里有很多非常令人困惑的答案。 让我尝试准确地回答你的问题。 让我们简化一下:
编译器如何解释最后一行? 编译器面临的问题是两个分支的条件表达式的类型必须一致; 语言规则不允许您在一个分支上返回 object 而在另一分支上返回 int 。 选项是 object 和 int。 每个 int 都可以转换为 object,但并非每个 object 都可以转换为 int,因此编译器选择 object。 相同
因此这与因此返回的零是一个装箱 int
。 然后将 int 拆箱为十进制。 将装箱 int 拆箱为十进制是非法的。 有关原因,请参阅我关于该主题的博客文章:
表示和身份< /a>
基本上,你的问题是你的行为就好像转换为十进制是分布式的,如下所示:
但正如我们所看到的,这不是这个
意思。 这意味着“将两种选择都制作成对象,然后将结果对象拆箱”。
UPDATE: This question was the subject of my blog on May 27th 2010. Thanks for the great question!
There are a great many very confusing answers here. Let me try to precisely answer your question. Let's simplify this down:
How does the compiler interpret the last line? The problem faced by the compiler is that the type of the conditional expression must be consistent for both branches; the language rules do not allow you to return object on one branch and int on the other. The choices are object and int. Every int is convertible to object but not every object is convertible to int, so the compiler chooses object. Therefore this is the same as
Therefore the zero returned is a boxed int.
You then unbox the int to decimal. It is illegal to unbox a boxed int to decimal. For the reasons why, see my blog article on that subject:
Representation and Identity
Basically, your problem is that you're acting as though the cast to decimal were distributed, like this:
But as we've seen, that is not what
means. That means "make both alternatives into objects and then unbox the resulting object".
不同之处在于编译器无法确定
Object
和Int32
之间良好匹配的数据类型。您可以将
int
值显式转换为object
,以在第二个和第三个操作数中获取相同的数据类型,以便进行编译,但这当然意味着您正在装箱并且拆箱该值:这将编译,但不会运行。 您必须将十进制值装箱才能将其拆箱为十进制值:
The difference is that the compiler can not determine a data type that is a good match between
Object
andInt32
.You can explicitly cast the
int
value toobject
to get the same data type in the second and third operand so that it compiles, but that of couse means that you are boxing and unboxing the value:That will compile, but not run. You have to box a decimal value to unbox as a decimal value:
运算符的类型将是 object,如果结果必须为 0,它将被隐式装箱。 但默认情况下 0 文字具有 int 类型,因此您可以将 int 框起来。 但是,通过显式转换为十进制,您尝试将其拆箱,这是不允许的(装箱类型必须与您转换回的类型相当)。 这就是为什么你可以获得例外。
以下是 C# 规范的摘录:
?: 运算符的第二个和第三个操作数控制条件表达式的类型。 设 X 和 Y 为第二个和第三个操作数的类型。 那么,
条件表达式。
条件表达式。
The type of the operator will be object and in case the result must be 0 it will be implicitly boxed. But 0 literal is by default has int type so you box int. But with explicit cast to decimal you try to unbox it which is not permitted (boxed type must much with the one you cast back to). That is why you can get exception.
Here is an excerpt from C# Specification:
The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,
conditional expression.
conditional expression.
您的行应该是:
0m 是零的十进制常量
条件运算符的两个部分应计算为相同的数据类型
Your line should be:
0m is the decimal constant for zero
Both parts of a conditional operator should evaluate to the same data type
x : y 部分需要一个通用类型,数据库的值可能是某种 float 类型,0 是 int 类型。 这发生在转换为十进制之前。 尝试“:0.0”或“:0D”。
The x : y part need a common type, the database's value is likely some kind of float and 0 is an int. This happens before the cast to decimal. Try ": 0.0" or ": 0D".
除非我弄错了(这很可能),它实际上是 0 导致了异常,这取决于 .NET(疯狂地)假设文字的类型,因此您需要指定 0m 而不仅仅是 0。
请参阅 MSDN 了解更多信息。
Unless I'm mistaken (which is very possible) its actually the 0 that's causing the exception, and this is down to .NET (crazily) assuming the type of a literal so you need to specify 0m rather than just 0.
See MSDN for more info.
有两种不同的类型供编译器决定(在编译时)将哪一种转换为十进制。 这是做不到的。
There are two different types for the compiler to decide (at compile time) which one to cast to decimal. This it can't do.
如果你将两者结合起来,你的答案就会起作用:
至少,类似的情况对我来说是一个参数。
Your answer would work if you combined both:
At least, a similar situation casting into a parameter for me.