可空类型和三元运算符:为什么是' ?10: null '禁止?

我刚刚发现了一个奇怪的错误:

private bool GetBoolValue()
{
//Do some logic and return true or false
}

然后,在另一种方法中,像这样:

int? x = GetBoolValue() ? 10 : null;

很简单,如果方法返回true,将10赋值给Nullableint x。否则,将null赋值给可以为空 int。然而,编译器抱怨:

错误1无法确定条件表达式的类型,因为在int<null>之间没有隐式转换。

我是不是疯了?

92183 次浏览

试试这个:

int? x = GetBoolValue() ? 10 : (int?)null;

基本上,发生的事情是条件操作符无法确定表达式的“返回类型”。由于编译器隐式地决定10是一个int,它随后决定该表达式的返回类型也应该是int。因为int不能是null(条件操作符的第三个操作数),它会抱怨。

通过将null转换为Nullable<int>,我们显式地告诉编译器这个表达式的返回类型应该是Nullable<int>。你也可以很容易地将10转换为int?,并获得相同的效果。

int? x = GetBoolValue() ? 10 : (int?)null;

你看到这个的原因是因为在幕后你正在使用Nullable,你需要告诉c#你的“null”是Nullable的一个空实例。

试试下面的方法:

int? x = GetBoolValue() ? (int?)10 : null;


int? x = GetBoolValue() ? 10 : (int?)null;

只需添加一个显式强制转换。

int? x = GetBoolValue() ? 10 : (int?)null;

混淆的是三元运算符——第二个参数是一个整数,因此第三个参数也应该是一个整数,null不合适。

问题是三元操作符是基于你的第一个参数赋值来推断类型的…在这个例子中是10,它是一个int型,不是一个可空的int型。

你的运气可能会更好:

int? x = GetBoolValue() (int?)10 : null;

编译器首先尝试求右边表达式的值:

GetBoolValue() ? 10 : null

10是一个int字面值(不是int?),而null是,嗯,null。这两者之间没有隐式转换,因此会出现错误消息。

如果将右边的表达式更改为以下表达式之一,则会编译,因为在int?null(#1)之间以及intint?(#2, #3)之间存在隐式转换。

GetBoolValue() ? (int?)10 : null    // #1
GetBoolValue() ? 10 : (int?)null    // #2
GetBoolValue() ? 10 : default(int?) // #3

这是因为编译器根据条件操作符的第二个和第三个操作数来确定它的类型,而不是根据你将结果赋值给什么。在编译器可以用来确定类型的整数和空引用之间没有直接的类型转换。

顺便说一句,微软的c#编译器实现实际上以一种非常微妙和有趣的方式(对我来说)错误地进行了条件操作符的类型分析。我的文章是类型推断的麻烦,第一部分(2006-05-24)。

试试这个:

int? result = condition ? 10 : default(int?);