逻辑短路求值--这个有保障吗? [C#]

17

在C#中关于短路语句有个问题。对于如下的if语句:

if (MyObject.MyArray.Count == 0 || MyObject.MyArray[0].SomeValue == 0)
{

//....
}

如果"MyArray.Count"部分为真,那么评估是否保证在那里停止?否则我会在第二部分得到一个空异常。


1
如果你问这个问题是因为你从上面的代码中得到了一个空引用异常,那很可能是因为MyArray为空或者MyArray[0]包含了一个空值。请看我的回答。 - Dan Tao
6个回答

37

是的,这是有保证的。

C#语言规范-7.11 条件逻辑运算符:

&&|| 运算符被称为条件逻辑运算符。它们也被称为“短路”逻辑运算符。

因此,它们将支持逻辑短路,你可以依赖这种行为。

现在重要的是要区分条件运算符和逻辑运算符:

  • 只有条件运算符支持短路,逻辑运算符不支持。
  • C#的逻辑运算符看起来与条件运算符相同,但少一个字符,所以逻辑或是|,逻辑与是&
  • 逻辑运算符可以重载,但条件运算符不能(这有点技术性,因为条件运算符的求值确实涉及重载决策,并且这个重载决策可以解析为类型的逻辑运算符的自定义重载,因此你可以在一定程度上绕过这个限制)。

语言规范在哪里? - Tim Schmelter

12

5

是的,这是有保证的,但是如果MyArray为null(或者MyObject显然也是如此),你仍然可能会遇到空引用异常。


2

仅供参考。

你说:

否则,第二部分会出现空异常。(强调我的)

实际上这是不正确的。如果短路不被保证,你可能会在第二部分得到IndexOutOfRangeException

如果你的MyArray对象中的第一项实际上为null(或者表达式中的任何其他对象为null),你仍然可能会得到NullReferenceException

唯一完全安全的检查方法是这样的:

bool conditionHolds =
    MyObject == null ||
    MyObject.MyArray == null ||
    MyObject.MyArray.Count == 0 ||
    MyObject.MyArray[0] == null ||
    MyObject.MyArray[0].SomeValue == 0;

if (conditionHolds)
{
    //....
}

1
我觉得你的意思是: 如果(条件不成立) - riffnl
@riffnl:不,我只是让我的例子与原帖的代码保持一致。(他/她似乎想在负面情况下使代码执行某些操作。) - Dan Tao

2
是的,
对于AND操作,如果任何一个操作数评估为false,则整个表达式评估为false,则无需评估剩余表达式。在OR操作中,如果任何一个操作数评估为true,则可以跳过其余的评估。
因此,通过使用&&或||运算符,可以在不评估所有子表达式的情况下将整个表达式评估为true或false。
但请考虑它的副作用。这篇文章可能有助于深入理解短路评估并提供一些实际示例。

-1

我更喜欢使用 && 运算符,因为这样你可以测试一个正面情况(我的数组包含项目),而不是负面情况(我的错误不包含项目):

if (MyObject.MyArray.Count > 0 && MyObject.MyArray[0].SomeValue == 0) 
{ 

//.... 
} 

这也保证要进行短路运算。


1
虽然这段代码与他的不同,如果计数为0,他的代码会短路并进入该块。而你的代码只有在第一个元素的值为0时才会进入该块。 - Anthony Pegram

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