Оценка короткого замыкания - это гарантировано? [С#]
Быстрый вопрос здесь о коротких замыканиях в С#. С помощью оператора if:
if (MyObject.MyArray.Count == 0 || MyObject.MyArray[0].SomeValue == 0)
{
//....
}
Гарантируется ли, что оценка остановится после части "MyArray.Count", если эта часть верна? В противном случае во второй части я получу нулевое исключение.
Ответы
Ответ 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)
{
//....
}
Это также гарантирует короткое замыкание.