Безопасно ли полагаться на короткое замыкание && в .NET?

Предположим, что myObj имеет значение null. Безопасно ли это писать?

if(myObj != null && myObj.SomeString != null)

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


person patrick    schedule 27.01.2011    source источник


Ответы (9)


да. В C# && и || являются короткими замыканиями и, таким образом, оценивают правую часть только в том случае, если левая сторона еще не определяет результат. С другой стороны, операторы & и | не замыкаются и всегда оценивают обе стороны.

Спецификация говорит:

Операторы && и || называются условными логическими операторами. Их также называют «замыкающими» логическими операторами.
...
Операция x && y соответствует операции x & y, за исключением того, что y вычисляется, только если x равно true
...
Операция x && y оценивается как (bool)x ? (bool)y : false. Другими словами, x сначала оценивается и преобразуется в тип bool. Затем, если x равно true, y оценивается и преобразуется в тип bool, и это становится результатом операции. В противном случае результатом операции будет false.

(Спецификация языка C#, версия 4.0–7.12, условные логические операторы)

Одно интересное свойство && и || заключается в том, что они замыкаются накоротко, даже если оперируют не логическими значениями, а типами, в которых пользователь перегрузил операторы & или | вместе с операторами true и false.

Операция x && y оценивается как T.false((T)x) ? (T)x : T.&((T)x, y), где T.false((T)x) — это вызов operator false, объявленного в T, а T.&((T)x, y) — это вызов выбранного operator &. Кроме того, значение (T)x оценивается только один раз.

Другими словами, x сначала оценивается и преобразуется в тип T, а operator false вызывается для результата, чтобы определить, является ли x определенно false.
Затем, если x определенно является false, результатом операции является значение, ранее вычисленное для x преобразуется в тип T.
В противном случае вычисляется y, и выбранный оператор & вызывается для значения, ранее вычисленного для x, преобразованного в тип T, и значения, вычисленного для y, для получения результата операции.

(Спецификация языка C#, версия 4.0 — 7.12.2 Пользовательские условные логические операторы)

person CodesInChaos    schedule 27.01.2011
comment
Последний абзац был немного слишком интересен... у меня заболела голова. :) - person Joe Enos; 27.01.2011
comment
Это выглядит сложно, но это не так сложно. Он просто не оценивает правую часть, если оператор false с левой стороны возвращает true и вместо этого возвращает левую сторону, а в противном случае вызывает пользовательский оператор &. Так что это имитирует короткое замыкание, которое есть у bool. Типичным применением этого является расширенный bool, который может иметь третье состояние. Например, вы можете реализовать что-то похожее на DBBol или bool?. - person CodesInChaos; 27.01.2011

Да, C# использует логическое сокращение.

Обратите внимание, что хотя C# (и некоторые другие языки .NET) ведут себя таким образом, это свойство языка, а не среды CLR.

person harpo    schedule 27.01.2011
comment
На самом деле VB.NET ведет себя таким образом при использовании AndAlso и OrElse, не при использовании And и Or, что, вероятно, всегда используют 90% людей. - person Adam Robinson; 27.01.2011
comment
Также важно отметить, что это не только деталь реализации (которая может измениться в любое время), но и часть спецификации C# (которая не изменится в этом отношении). - person Olivier Jacot-Descombes; 06.12.2017

Я знаю, что опаздываю на вечеринку, но в C# 6.0 это тоже можно сделать:

if(myObj?.SomeString != null)

Что то же самое, что и выше.

Также см.: Что делает вопрос оператор отметки и точки ?. значит в C# 6.0?

person Drew Delano    schedule 21.01.2016
comment
Ответ не отвечает на вопрос и представляет собой предложение по синтаксическому сахару, которое должно быть комментарием. - person Billy Bob; 25.03.2021
comment
@BillyBob Ответ на исходный вопрос ОП - да, и это было хорошо установлено всеми другими ответами здесь. Это больше подходит для ответа на вопрос, действительно ли приведенный пример кода нуждается в коротком замыкании. - person Drew Delano; 27.03.2021

Ваш код в безопасности - && и || оба короткозамкнуты. Вы можете использовать операторы без короткого замыкания & или |, которые оценивают оба конца, но я действительно не вижу этого в большом количестве производственного кода.

person Joe Enos    schedule 27.01.2011

конечно, на С# это безопасно, если первый операнд ложный, то второй никогда не оценивается.

person Mauricio    schedule 27.01.2011
comment
Если бы вы были одним из красивых людей, возможно, кто-то проголосовал бы за ваш ответ. - person Pedro; 28.01.2011
comment
Ваш ответ правильный, но не такой подробный, как CodesInChaos - person John Grabauskas; 11.10.2017

Это совершенно безопасно. C# — один из таких языков.

person Ilya Kogan    schedule 27.01.2011
comment
Один из тех языков, которые используют оценку короткого замыкания здесь - person Brad; 27.01.2011
comment
@ Адам, в вопросе говорится, что я знаю несколько языков ... - person Ilya Kogan; 27.01.2011
comment
@Илья Коган: Я думаю, это означает, что я должен более внимательно прочитать вопрос ;) - person Adam Robinson; 27.01.2011

Да, C# и большинство языков вычисляют предложения if слева направо.

Кстати, VB6 вычислит все это и выдаст исключение, если оно равно нулю...

person Yochai Timmer    schedule 27.01.2011
comment
Это... не совсем неправильно, но вводит в заблуждение на многих уровнях. (1) Языки с фигурными скобками — это лишь небольшое подмножество языков, которые это делают. (2) Реверсирование ввода перед его разбором - это безумие, поэтому ни один язык этого не делает. (3) Независимо от того, как он анализируется, укороченная схема — это семантика времени выполнения. (4) См. комментарий к ответу harpo относительно VB - And не закорачивает, но & тоже нет. (Возможно, 2+3 потому, что вы путаете синтаксический анализ с чем-то, что происходит во время выполнения...) - person ; 27.01.2011

пример

if(strString != null && strString.Length > 0)

Эта строка вызовет нулевое исключение, если будут выполнены обе стороны.

Интересное примечание. Приведенный выше пример немного быстрее, чем метод IsNullorEmpty.

person Bengie    schedule 27.01.2011

В C# && и || замкнуты накоротко, что означает, что оценивается первое условие, а остальные игнорируются, если ответ определен.

В VB.NET AndAlso и OrElse также закорочены.

В javaScript && и || тоже закорочены.

Я упоминаю VB.NET, чтобы показать, что у уродливого рыжеволосого приемного ребенка .net тоже иногда есть интересные вещи.

Я упоминаю javaScript, потому что если вы занимаетесь веб-разработкой, вы, вероятно, также можете использовать javaScript.

person John Grabauskas    schedule 11.10.2017
comment
По существу, a || b эквивалентно a ? a : b, а a && b эквивалентно a ? b : a, за исключением того, что вычисляется только один раз. Это более заметно в JavaScript, где могут использоваться операнды произвольного типа. Другие языки, такие как C, не следуют этому принципу — они принимают операнды небулевых типов, но всегда возвращают логическое значение. - person Stewart; 11.02.2020