为什么不能在可空类型中使用 && 和 || 运算符?

8
可能重复:AND operation cannot be applied between nullable bools. 我希望它的行为类似于+或*。因此,如果操作数中有任何一个为null,则应返回null,但是如果在&&或||中使用它,则编译器会发出警告。为什么?
举个例子:
//this compiles
int? x = null;
int? y = null;
var z = x*y;

// this doesn't compile
bool? x = null;
bool? y = null;
if(x && y)
    ....

1
你能提供一些失败的示例代码吗? 我不确定我理解你指的是什么。 - Karl Nicoll
5
如果任何操作数为null,则应返回null:&&||运算符属于布尔类型,因此始终返回布尔结果。如果您使用可空类型,只需使用myNullable.HasValue && ... - Dirk Vollmar
可能是重复的问题:无法在可空布尔值之间应用AND操作。请参见Eric Lippert的优秀答案和他提供的示例。 - Dirk Vollmar
抱歉重复了。我现在明白为什么它在本质上不受支持,尽管在某些情况下可能是有道理的。 - newman
4个回答

10

如果返回null,那么您就无法满足布尔需求。

|| &&

基本上,这将允许在if语句中使用除bool(具体而言是null)以外的值,这会导致未定义行为,因为if语句要求布尔表达式。

有趣的是,这是Java和C#之间的差异之一。Java也要求if语句中使用布尔值,但它们允许其版本的bool?Nullable<bool>或Java中的Boolean)可以是null。这会导致运行时出现意外的NullPointerException,而C#通过此要求避免了这种情况。


2

可能是因为&&和||是短路运算符。你可以在bool?中使用&和|,我相信你会得到三值逻辑 - null被视为"未知"。所以false&null是false,但true&null是null。这已经很令人困惑了,不要再加入短路运算符了!面对null值,短路运算可能实际上并没有什么用处。

编辑-考虑后,短路运算对于三值逻辑仍然有意义。左边为false的逻辑AND将始终计算为false,即使右边是null。左边为true的逻辑OR将始终计算为true,即使右边是null。我想这是那些"不值得实现"功能之一。有时需要短路布尔逻辑。有时需要三值布尔逻辑。但是两者很少重叠。


+1 不知道 ¦ 和 & 是否被实现为布尔类型? - Danny Varod
1
短路可空布尔值的问题在于,如果你有(null && M()),你该怎么办?你要评估M()还是不评估?请记住,null可能意味着“存在一个真值,但我现在不知道它是什么”。如果左侧为true,则M()可能具有应该被评估的副作用,但我们不知道它是否为true。编译器不会为您做出“我不知道”应该被视为“false”的决定 - 如果事实证明它应该是true呢? - Eric Lippert
啊,谢谢。我认为这是不同的心智模型。在我的脑海中,我认为三值逻辑AND有两个输入和一个输出,有一个九项真值表,然后将短路视为过程:“从左到右评估输入表达式,直到输出明确”,到这一点上,我只是认为null是另一个值 - 我并没有将其视为特殊的超级位置。当您将“a && b”视为“评估a,如果为false,则返回false,否则评估并返回b”时,它就更有意义了。 - Weeble

0
即使 (x && y) 是可能的,结果也将是 bool? 而不是 bool。if () 只适用于 bool。
请尝试使用 if (((bool)(x ?? false)) && (bool)(y ?? false))。
或者更好的方法是遵循 weebles 的答案:
如果 (x & y == true)。

-3

可空类型实际上是对象。当您将可空运算符“?”应用于值类型(例如bool)时,它变成了对一个对象的引用,该对象保存“null”或基础值类型的值。

考虑以下情况:

bool? isActive;

这实际上变成了:

Nullable<bool> isActive;

值类型实际上成为一个对象实例,因此不像常规值类型那样参与布尔表达式。

更多信息:http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx


6
完全错误。Nullable<T>是一个结构体;没有装箱操作涉及到。 - SLaks
-1,您使用的术语令人困惑。Nullable<T>是一个结构体,因此可空类型是类型,因此您没有对可空类型的引用 - Dirk Vollmar
谢谢大家的负评,但是事实上,对于非空类型,Nullable<T> 确实会进行装箱操作。此外,Nullable<T> 是从 Object 类派生的。 - jscharf
2
@jscharf:从Object派生并不意味着该类型需要装箱。实际上,结构体、枚举和任何值类型都继承自Object。 - Quan Mai
从技术上讲,不完全是这样的。它们在被装箱后才会这样。非空 Nullable 的最终结果仍然以 Object 的形式存储在堆上,这就是为什么它不能隐式用于布尔表达式的原因,这也是我的观点。 - jscharf
@jscharf:这个问题与拳击无关。当然,可空值类型(如果它们是非空的,则作为基础非可空值类型)可以被装箱,但这与&&||仅定义在bool上没有任何关系。 - Dirk Vollmar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接