可空布尔值之间不能应用AND操作。

9

我正在两个可空布尔型 (bool?) 之间应用 AND 操作符 (&&),但是它报错了:

运算符 && 不能用于类型为 bool?bool? 的操作数

在包含两个可空布尔值的语句中如何应用 and 操作符?

此外,如果我有一个对话框结果如下:

dialog.ShowDialog () == DialogResult.OK

如何将它转换为可空的布尔值,因为我需要在if条件语句中与返回可空布尔值的另一个操作数使用'&&'运算符?以下是代码:

if (dialog.ShowDialog () == DialogResult.OK && CheckProjectPath(dialog.FileName, true))

这个if条件语句中的第二个操作数是一个可空布尔值。

左操作数不能为可空类型,而第二个操作数返回可空布尔值。现在我得到的编译错误是运算符“&&”无法应用于类型为“bool”和“bool?”的操作数。 - ghd
你的CheckProjectPath方法的结果是Nullable布尔值吗? - jvanrhyn
3
对于 true && null,您需要什么行为? - Ani
第二个操作数是可空布尔值,它不一定为null。我有一个带有“是”,“否”,“取消”选项的消息框,因此我需要三个布尔值。 - ghd
5个回答

22
我如何在包含两个可空布尔值的语句中应用与操作? 好的,你想要什么结果?不允许这样做的原因是如果第一个操作数为null,则会发生不良事件。 对于可空布尔值x和y,x && y是什么意思?那么,首先,可空布尔值的意思是什么呢?可空布尔值有三种可能:
  • 条件肯定为真
  • 条件肯定为假
  • 条件为true或false,但我们不知道是哪一个
那么,x && y是什么意思呢?它的意思是“只有当条件x为真时才评估y”,但如果x是可空的,则我们可能不知道由x所代表的条件是否为真。 例如,假设我们有:
gotMoneyInZurich = SalesForNovemberWereMoreThanAMillionBucks() &&
    TryToDepositAMillionBucksInASwissBankAccount();
如果 SalesForNovemberWereMoreThanAMillionBucks 为假,则不尝试存钱,我们知道银行里没有钱。如果为真,则尝试存钱;如果失败,则我们在苏黎世没有钱;如果成功则有钱。
现在假设并非所有销售人员都报告了他们11月份的销售数据。那么我们是否知道11月的销售额是否超过了一百万美元呢?不是的。11月已经过去了;11月份的销售额无论是超过一百万美元还是低于它,现在我们都不知道。正确的答案既不是“假”,也不是“真”:正确的答案是“我们不知道”:null。
那么如果第一个操作数返回 null,应该怎么办呢?我们不知道销售额是否超过了一百万美元,所以采取行动是正确的吗?还是不采取行动呢?根据缺失信息采取行动,还是不采取行动?
编译器没有能力为您决定这个问题。如果您想在结果未知时不存钱,则必须说:(SalesForNovemberWereMoreThanAMillionBucks() ?? false) 意味着“如果结果为 null,则将其视为 false ”。
同样,如果您说:
if(x && y)
    Frob();

如果x为真,y为空,那么你应该怎么做?你说:“只有当x和y都为真时才进行Frob。x为真,我们不知道y是否为真。”那么你应该进行Frob吗?你不知道编译器也不知道。 如果你想表达的是“只要x为真且y为真或为空时才进行Frob”,那么就这样说:

if(x && (y ?? true))
    Frob();

或者,如果 x 为真且 y 为真,但 y 为 null 则不 frob,则说:

if(x && (y ?? false))
    Frob();
如果你不是出于短路求值的目的,就不要使用 && 运算符。这时候可以使用 & 运算符,它总是会评估两边表达式,因此不会存在歧义。如果 xy 是可空布尔类型,那么使用 x & y 是完全合法的。当然你仍然不能在 if 语句中使用这个东西,因为它需要一个布尔类型而不是可空布尔类型。但你可以这样写: bool? result = x & y; 其中 xy 是可空布尔类型。

1
如果x或y为null,则“结果将为null,如果x和y都为true,则为true,否则为false”是不正确的;请参见此处。我认为更好的方法是说,如果任何一个值为false(一个false值使and为假),则a&bfalse,如果两个值都为true,则为true,否则为null。同样,如果任何一个值为true(一个true值满足or),则a|btrue,如果两个值都为false,则为false,否则为null - Adam
2
@Adam:我已经在编译器中实现了这些规则;你会认为我能够正确地描述它们。 :) 感谢您的提醒。 - Eric Lippert
1
谢谢 :) 我承认当我看到你是答案的作者时,我进行了四倍的检查。 - Adam

7

你可以使用类似于

bool? b1 = ...;
bool? b2 = ...;    
bool b = (b1 ?? true) && (b2 ?? false);

你需要选择自己的默认值。
如何将其转换为可空布尔值,因为我需要在if条件中使用“&&”运算符,其另一个操作数返回可空布尔值?
你应该走另一条路:无法对可空操作数进行操作,因此您必须尝试从bool?转换为bool。在这里,运算符??非常有用:
 if (dialog.ShowDialog () == DialogResult.OK 
     && CheckProjectPath(dialog.FileName, true) ?? false)

关于 "空值合并运算符" ?? :

int? a, b, c;
...
int d = a ?? b ?? c ?? -1;

如果a、b和c都是null,则d变为-1。如果它们中任何一个不是null,则使用第一个值。

我不理解这里"??"运算符的用法。如果左操作数不为空,它将返回左操作数;否则,它将返回右操作数。 - ghd

1

我只是猜测,你可以试试看

if ((dialog.ShowDialog() == DialogResult.OK )&& 
            (CheckProjectPath(dialog.FileName, true) == true ) )

是的,但有些麻烦。你不能在bool中使用&&,但当你使用==时它总是为false。请注意,以... == false))结尾将得到相同的答案。 - H H
你的意思是如果 (CheckProjectPath(dialog.FileName, true) 为 null 呢? 然而我们同时回答了,当我读到你的答案时,我发现我的是一个变通方法。我只是认为 == 运算符会返回一个布尔值而不是可空布尔值。 - Frabu

1
if (dialog.ShowDialog () == DialogResult.OK &&
    CheckProjectPath(dialog.FileName, true).GetValueOrDefault())

&& 操作对于 null 值是未定义的。因此,您必须确保两个布尔值都不可为空,并且最简单的方法是调用可空布尔值的 GetValueOrDefault() 方法。


0
if (dialog.ShowDialog () == DialogResult.OK) 
{
    var checkProjectPath =  CheckProjectPath(dialog.FileName, true);
    if (checkProjectPath.HasValue && checkProjectPath)) {/*Your Action*/}
}

如果 CheckProjectPath 函数的目的是验证路径,我看不出为什么结果应该是 bool?。

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