【问题标题】:Conditional Operator ?: with Nullable type Casting条件运算符?:具有可空类型转换
【发布时间】:2013-09-17 07:37:54
【问题描述】:

从 MSDN 文档中,以下两个 sn-ps 是相等的:

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

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

太棒了,太棒了。我用它所有的时间。简洁有效。

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

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 块。

【问题讨论】:

  • @NickGotch 我看过你的帖子,但老实说我对答案不满意。我想了解为什么在使用一种语法而不是另一种时需要强制转换。
  • 我认为在这种情况下你可以只做x = value,还是我错了?

标签: c# .net


【解决方案1】:

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

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

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


回答cmets中的问题:

为什么它不是隐含的?
是的,我明白了。但是为什么我不必将其转换为 If Else 块?

让我们看一下代码。

您的else 语句如下所示:

else x = null;

这意味着您将null 的值分配给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 的回答中,您可以将石膏放在左侧或右侧。

【讨论】:

  • 为什么它不是隐含的?
  • 是的,我明白了。但为什么我不必将其转换为 If Else 块?
  • @gunr2171 啊哈!是的,现在这很有意义。只是为了澄清; ?: 运算符需要所有 3 个操作数的单一数据类型,是吗?或者,至少,一种可转换的类型。
  • @Michael,有点像。 “条件”需要一个布尔值,引用msdnEither the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.null 没有与其他人的隐式转换)。
【解决方案2】:
var x = value.HasValue ? value.Value : default(int?);

也可以。

【讨论】:

    【解决方案3】:

    对于Condtional operator MSDN 状态:

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

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

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

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

    所以:

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

    或者

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

    很好。

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

    【讨论】:

      【解决方案4】:

      documentation for the ?: operator 声明表达式 b 的类型? x : y 是通过检查 x 和 y 的类型来确定的:

      • 如果 X 和 Y 是同一类型,则这是条件表达式的类型。
      • 否则,如果存在从 X 到 Y 而不是从 Y 到 X 的隐式转换(第 6.1 节),则 Y 是条件表达式的类型。
      • 否则,如果存在从 Y 到 X 而不是从 X 到 Y 的隐式转换(第 6.1 节),则 X 是条件表达式的类型。
      • 否则无法确定表达式类型,并出现编译时错误。

      在你的例子中

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

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

      【讨论】:

      • 我认为这是最好的答案,虽然转换为什么不使用b 来确定类型?
      【解决方案5】:

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

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

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

      更多解释请参见第 7.14 节(条件运算符)和第 7.17.1 节(简单赋值)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-22
        • 1970-01-01
        • 2012-09-24
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多