C# ?: 条件运算符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1171717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# ?: Conditional Operator
提问by Ioannis
I have this extract of C# 2.0 source code:
我有这个 C# 2.0 源代码的摘录:
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?
第一个结果评估抛出一个InvalidCastException
而第二个则没有。这两者有什么区别?
采纳答案by Eric Lippert
UPDATE: This question was the subject of my blog on May 27th 2010. Thanks for the great question!
更新:这个问题是我 2010 年 5 月 27 日博客的主题。谢谢你的好问题!
There are a great many very confusing answers here. Let me try to precisely answer your question. Let's simplify this down:
这里有很多非常令人困惑的答案。让我试着准确地回答你的问题。让我们简化一下:
object value = whatever;
bool condition = something;
decimal result = (decimal)(condition ? value : 0);
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
编译器如何解释最后一行?编译器面临的问题是两个分支的条件表达式的类型必须一致;语言规则不允许您在一个分支上返回对象,而在另一个分支上返回 int。选项是 object 和 int。每个 int 都可以转换为 object,但不是每个 object 都可以转换为 int,因此编译器选择 object。因此这与
decimal result = (decimal)(condition ? (object)value : (object)0);
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:
然后将 int 拆箱为十进制。将装箱的 int 拆箱为十进制是非法的。至于原因,请参阅我关于该主题的博客文章:
Basically, your problem is that you're acting as though the cast to decimal were distributed, like this:
基本上,你的问题是你的行为好像是分配到十进制的,就像这样:
decimal result = condition ? (decimal)value : (decimal)0;
But as we've seen, that is not what
但正如我们所见,这不是
decimal result = (decimal)(condition ? value : 0);
means. That means "make both alternatives into objects and then unbox the resulting object".
方法。这意味着“将两个选项都放入对象中,然后将生成的对象拆箱”。
回答by Guffa
The difference is that the compiler can not determine a data type that is a good match between Object
and Int32
.
不同之处在于编译器无法确定Object
和之间的良好匹配的数据类型Int32
。
You can explicitly cast the int
value to object
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:
您可以显式地将int
值强制转换object
为在第二个和第三个操作数中获得相同的数据类型,以便它进行编译,但这当然意味着您正在装箱和拆箱该值:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0);
That will compile, but not run. You have to box a decimal value to unbox as a decimal value:
那会编译,但不会运行。您必须装箱一个十进制值才能取消装箱为十进制值:
result = (decimal)(valueFromDatabase != DBNull.value ? valueFromDatabase : (object)0M);
回答by Donald Byrd
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".
x : y 部分需要一个通用类型,数据库的值可能是某种浮点数,0 是一个整数。这发生在转换为十进制之前。尝试“:0.0”或“:0D”。
回答by Dzmitry Huba
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.
运算符的类型将是对象,如果结果必须为 0,它将被隐式装箱。但是 0 文字默认具有 int 类型,因此您将 int 装箱。但是通过显式转换为十进制,您尝试将其拆箱,这是不允许的(装箱类型必须与您转换回的类型相同)。这就是为什么你可以得到例外。
Here is an excerpt from C# Specification:
以下是 C# 规范的摘录:
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,
?: 运算符的第二个和第三个操作数控制条件表达式的类型。设 X 和 Y 是第二个和第三个操作数的类型。然后,
- If X and Y are the same type, then this is the type of the conditional expression.
- Otherwise, if an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
- Otherwise, if an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
- Otherwise, no expression type can be determined, and a compile-time error occurs.
- 如果 X 和 Y 是相同类型,则这是条件表达式的类型。
- 否则,如果存在从 X 到 Y 的隐式转换(第 6.1 节),但不存在从 Y 到 X 的隐式转换,则 Y 是条件表达式的类型。
- 否则,如果存在从 Y 到 X 的隐式转换(第 6.1 节),但不存在从 X 到 Y 的隐式转换,则 X 是条件表达式的类型。
- 否则,无法确定表达式类型,并发生编译时错误。
回答by Mark
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.
除非我弄错了(这很有可能)它实际上是导致异常的 0,这归结为 .NET(疯狂)假设文字类型,因此您需要指定 0m 而不仅仅是 0。
See MSDNfor more info.
有关更多信息,请参阅MSDN。
回答by Ioannis
There are two different types for the compiler to decide (at compile time) which one to cast to decimal. This it can't do.
编译器有两种不同的类型来决定(在编译时)将哪一种转换为十进制。这是做不到的。
回答by Philippe Leybaert
Your line should be:
你的线路应该是:
result = valueFromDatabase != DBNull.value ? (decimal)valueFromDatabase : 0m;
0mis the decimal constant for zero
0m是零的十进制常数
Both parts of a conditional operator should evaluate to the same data type
条件运算符的两个部分都应评估为相同的数据类型
回答by Give_Us_The_Money_Lebowski
Your answer would work if you combined both:
如果您将两者结合起来,您的答案将起作用:
result = (decimal)(valueFromDatabase != DBNull.Value ? (decimal)valueFromDatabase : (decimal)0);
At least, a similar situation casting into a parameter for me.
至少,类似的情况对我来说是一个参数。