条件运算符?:具有Nullable类型的Casting

从MSDN文档中,以下两个片段是相同的:

bool value; int x = (value) ? 0 : 1; 

 bool value; int x; if (value) x = 0; else x = 1; 

太好了,很棒。 我用它所有的时间。 Terse和有效。

如果我们尝试使用可空类型,如下所示:

 int? x = (value.HasValue) ? value.Value : null; 

我们得到一个编译时错误:

 The type of conditional expression cannot be determined because there is no implicit conversion between '{NullableType}' and null. 

编译好:

 int? value; int? x; if (value.HasValue) x = value.Value; else x = null; 

所以,我理解编译器需要以(int?)null的方式进行显式转换以编译第一个语句。 我不明白的是为什么在该声明中需要它,而不是If Else块。

null可以表示任何基于对象的数据类型。 您需要将null为数据类型,以便它知道您在说什么。

 int? x = (value.HasValue) ? value.Value : (int?)null; 

我知道,这听起来有点奇怪。


要回答评论中的问题:

为什么不隐含呢?
是的,我明白了。 但为什么我不必将它放在If Else块中呢?

让我们来看看代码吧。

你的else语句如下所示:

 else x = null; 

这意味着您要将nullnull x 。 这是有效的,因为x是一个int?nulls

当你有三元运算符时,差异就出现了。 它说:“将运算符的值分配给x ”。 问题(以及您的错误的原因)是,三元运算符的结果是什么数据类型?

从您的代码中,您无法确定,并且编译器会举起手来。

 int? x = (value.HasValue) ? value.Value : null; // int? bool int ?? 

什么数据类型为null ? 你很快就会说“好吧它是一个int?因为另一边是一个int ,结果是一个int? ”。 问题是,如下:

 string a = null; bool? b = null; SqlConnectionStringBuilder s = null; 

这也是有效的,这意味着null可以用于any object-based datatype 。 这就是为什么你必须显式地将null为你想要使用的类型,因为它可以用于任何事情!


另一种解释(可能更准确):

您不能在可空值和非可空值之间进行隐式转换。

int是不可为空的(它是一个结构),其中null是。 这就是为什么在Habib的回答中你可以把演员放在左侧或右侧。

对于Condtional运营商MSDN状态:

first_expression和second_expression的类型必须相同 ,或者从一种类型到另一种类型必须存在隐式转换

所以在你的情况下你的first_expression和second_expression是:

 int? x = (value.HasValue) ? value.Value : null; ^^^^^^^^ ^^^^^ first exp 2nd Exp 

现在,如果你看到,你的First Expression是int类型,第二个表达式是null ,两者都不相同,也没有隐式转换。 所以将它们中的任何一个转换为`int? 解决了这个问题。

所以:

 int? x = (value.HasValue) ? (int?) value.Value : null; 

要么

 int? x = (value.HasValue) ? value.Value : (int?) null; 

没事。

现在为什么if-else不需要它,因为涉及多个语句而且它不是分配值的单个语句。

 var x = value.HasValue ? value.Value : default(int?); 

也有效。

?:运算符的文档说明了表达式b的类型? x:y是通过检查x和y的类型来确定的:

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

在你的例子中

 int? x = (value.HasValue) ? value.Value : null; 

int和null之间没有隐式转换,因此最后一个项目符号适用。

原因是条件表达式的类型由条件运算符(?:)的第二个和第三个运算符确定。

由于null没有类型,因此编译器无法确定整个表达式的类型,因此会发出编译器错误。

它与简单赋值运算符(=)一起使用的原因是因为运算符的左侧确定了类型。 因为在If语句中,x的类型已经知道,所以编译器不会抱怨。

有关详细说明,请参见第7.14节(条件运算符)和第7.17.1节(简单赋值)。