Подтвердить что ты не робот

Оценка короткого замыкания - это гарантировано? [С#]

Быстрый вопрос здесь о коротких замыканиях в С#. С помощью оператора if:

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

//....
}

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

4b9b3361

Ответ 1

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

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

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

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

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

  • Только условные операторы поддерживают короткое замыкание, логические операторы этого не делают.
  • Логические операторы С# выглядят точно так же, как и их условные копии, но с одним меньшим символом, поэтому логическое ИЛИ - |, а логическое И - &.
  • Логические операторы могут быть перегружены, но условные операторы не могут (это немного технически, поскольку оценка условного оператора связана с разрешением перегрузки, и это разрешение перегрузки может разрешить пользовательскую перегрузку логического оператора типа, поэтому вы можете обойти это ограничение в определенной степени).

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

Просто небольшое наблюдение.

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

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

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

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

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

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

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

Ответ 5

Да,

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

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

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

Ответ 6

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

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

//.... 
} 

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