Оценка короткого замыкания гарантируется? [C #]

Быстрый вопрос об операторах короткого замыкания в C #. С таким выражением if:

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

//....
}

Гарантируется ли, что оценка остановится после части "MyArray.Count", если эта часть верна? В противном случае я получу нулевое исключение во второй части.


person larryq    schedule 22.04.2010    source источник
comment
Если вы задаете этот вопрос, потому что вы действительно получили исключение нулевой ссылки из приведенного выше кода, это, скорее всего, потому, что MyArray имеет значение NULL или MyArray[0] содержит значение NULL. Смотрите мой ответ.   -  person Dan Tao    schedule 22.04.2010


Ответы (6)


Да, это гарантировано.

Спецификация языка C # - 7.11 Условные логические операторы:

Операторы && и || называются условными логическими операторами. Их также называют логическими операторами "короткого замыкания".

Поэтому они будут поддерживать логическое замыкание по определению - на такое поведение можно положиться.

Теперь важно различать условный оператор и логический оператор:

  • Только условные операторы поддерживают короткое замыкание, логические операторы - нет.
  • Логические операторы C # выглядят так же, как их условные аналоги, но с одним символом меньше, поэтому логическое ИЛИ равно |, а логическое И равно &.
  • Логические операторы могут быть перегружены, но условные операторы - нет (это небольшая техническая часть, поскольку оценка условного оператора включает разрешение перегрузки, и это разрешение перегрузки может разрешаться в настраиваемую перегрузку логического оператора типа, поэтому вы можете обойти это ограничение до определенной степени).
person Andrew Hare    schedule 22.04.2010
comment
Где спецификация языка? - person Tim Schmelter; 18.03.2021

Да, это гарантировано.

http://msdn.microsoft.com/en-us/library/6373h346%28v=VS.80%29.aspx

Оператор условного ИЛИ (||) выполняет логическое ИЛИ своих логических операндов, но при необходимости оценивает только второй операнд.

person Bryan Watts    schedule 22.04.2010

Да, это гарантировано, но вы все равно можете получить исключение с нулевой ссылкой, если MyArray имеет значение null (или MyObject, если на то пошло, очевидно).

person kemiller2002    schedule 22.04.2010

Небольшое наблюдение.

Вы сказали это:

В противном случае я получу нулевое исключение во второй части. (подчеркивает мой)

На самом деле это неправда. Если бы короткое замыкание не было гарантировано, вы могли бы получить IndexOutOfRangeException во второй части.

все еще возможно, что вы могли бы получить NullReferenceException, если первый элемент в вашем MyArray объекте на самом деле имеет значение null (или если какой-либо из других объектов в этом выражении имеет значение).

Единственная полностью безопасная проверка:

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

if (conditionHolds)
{
    //....
}
person Dan Tao    schedule 22.04.2010
comment
Я думаю, вы скажете: if (! ConditionHolds) - person riffnl; 22.04.2010
comment
@riffnl: Нет, я просто приводил свой пример в соответствие с кодом OP. (Кажется, он / она хочет, чтобы код что-то делал в отрицательном случае.) - person Dan Tao; 22.04.2010

Да,

Для операций И, если какой-либо из операндов оценивается как ложь, тогда общее выражение оценивается как ложное, тогда нет необходимости оценивать оставшиеся выражения, а в случае операции ИЛИ, если какой-либо из операндов оценивается как истинное, оставшаяся оценка может быть пропущена

Итак, используя && или || оператор, все выражение может быть оценено как истинное или ложное без оценки всех подвыражений.

Но рассмотрите также его побочный эффект. Эта статья может быть полезна для понимания оценки короткого замыкания. подробно с некоторыми примерами из реального мира.

person Shamseer K    schedule 01.05.2016

Я предпочитаю использовать оператор &&, потому что тогда вы проверяете положительный результат (мой массив содержит элементы), а не отрицательный (моя ошибка не содержит элементов):

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

//.... 
} 

Это также гарантирует короткое замыкание.

person Polyfun    schedule 22.04.2010
comment
Однако результат этого кода не такой, как у него. В его случае, если счетчик равен 0, он замыкается и входит в блок. В вашем он только входит в блок, когда значение первого элемента равно 0. - person Anthony Pegram; 22.04.2010