Ответ 1
С#: Слева направо, и обработка останавливается, если найден несоответствие (оценивается как false).
В С# (и не стесняйтесь отвечать на другие языки), какой порядок выполнения оценивает логический оператор?
Пример:
DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
//do some stuff with myDt
}
Какой оператор оценивает среду выполнения -
myDt != null
или
myDt.Rows.Count > 0
?
Есть ли время, когда компилятор когда-либо оценивал выражение назад? Возможно, когда задействуется оператор "OR"?
& известен как логический побитовый оператор и всегда будет оценивать все подвыражения
Каков хороший пример того, когда использовать побитовый оператор вместо "короткозамкнутого логического"?
С#: Слева направо, и обработка останавливается, если найден несоответствие (оценивается как false).
"С#: Слева направо, и обработка останавливается, если найдено совпадение (значение true).
Зомби-овцы ошибаются, недостаточно репутации, чтобы проголосовать за нее.
Вопрос о && оператора, а не || Оператор.
В случае && оценка остановится, если найден FALSE.
В случае || оценка останавливается, если найден TRUE.
Я понимаю, что этот вопрос уже ответил, но я хотел бы добавить еще немного информации, которая связана с темой.
В языках, таких как С++, где вы действительно можете перегружать поведение && и || операторов, настоятельно рекомендуется, чтобы вы не делали этого. Это связано с тем, что когда вы перегружаете это поведение, вы в конечном итоге заставляете оценивать обе стороны операции. Это делает две вещи:
Для получения дополнительной информации прочитайте книгу Скотта Мейерса Более эффективный С++. Ура!
vb.net
if( x isNot Nothing AndAlso x.go()) then
Вы можете использовать И вместо AndAlso в vb. в этом случае сначала оценивается левая сторона, но правая сторона будет оцениваться независимо от результата.
Лучшая практика: всегда используйте AndAlso, если у вас нет веских причин, почему бы и нет.
В ответ на вопрос, почему или когда кто-нибудь будет использовать And вместо AndAlso (или вместо & &): Вот пример:
if ( x.init() And y.init()) then
x.process(y)
end
y.doDance()
В этом случае я хочу инициализировать как X, так и Y. Y должен быть инициализирован для того, чтобы y.DoDance мог выполнить. Тем не менее, в функции init() я также выполняю некоторые дополнительные действия, такие как проверка сокета, и только если это работает нормально, для обоих, я должен продолжить и выполнить x.process(у).
Опять же, это, вероятно, не нужно, а не изящно в 99% случаев, поэтому я сказал, что по умолчанию должно быть использование AndAlso.
@shsteimer
Концепция скромности имеет в виду перегрузку оператора. в заявлении:... Сначала оценивается A, если он оценивается как false, B никогда не оценивается. То же самое относится к
Это не перегрузка оператора. Перегрузка оператора - это термин, заданный для определения пользовательского поведения для операторов, таких как *, +, = и т.д.
Это позволит вам написать собственный класс "Журнал", а затем сделать
a = new Log(); // Log class overloads the + operator
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.
Выполнение этого
a() || b() // be never runs if a is true
на самом деле называется Оценка короткого замыкания
ZombieSheep мертв. Единственная "получаемая", которая может быть ожидающей, заключается в том, что это верно только в том случае, если вы используете && оператор. При использовании оператора и, оба выражения будут оцениваться каждый раз, независимо от того, будет ли один или оба равным false.
if (amHungry & whiteCastleIsNearby)
{
// The code will check if White Castle is nearby
// even when I am not hungry
}
if (amHungry && whiteCastleIsNearby)
{
// The code will only check if White Castle is nearby
// when I am hungry
}
Обратите внимание, что существует разница между && и о том, какая часть вашего выражения оценивается.
& & известен как короткозамкнутый логический И, и, как отмечают другие здесь, останавливается раньше, если результат может быть определен до того, как будут оценены все подвыражения.
& известен как логический побитовый оператор и всегда будет оценивать все подвыражения.
Таким образом:
if (a() && b())
Будет вызывать только b, если a возвращает true.
однако это:
if (a() & b())
Всегда вызывается как a, так и b, хотя результат вызова a является ложным и, следовательно, известен как false, независимо от результата вызова b.
Эта же разница существует для || и | операторы.
Некоторые языки имеют интересные ситуации, когда выражения выполняются в другом порядке. Я специально думаю о Ruby, но я уверен, что они заимствовали его из других источников (возможно, Perl).
Выражения в логике останутся слева направо, но, например:
puts message unless message.nil?
Вышеуказанное будет оценивать "message.nil?" сначала, если он оценивает значение false (если это не так, как если бы оно выполнялось, когда условие является ложным, а не истинным), выполняется "puts message", которое печатает содержимое переменной сообщения на экране.
Это своего рода интересный способ структурирования вашего кода иногда... Мне лично нравится использовать его для очень коротких 1 лайнеров, как указано выше.
Edit:
Чтобы сделать это немного яснее, вышесказанное совпадает с:
unless message.nil?
puts message
end
Левый, затем останавливается, если он равен нулю.
Изменить: В vb.net он будет оценивать обе и, возможно, выбросить ошибку, если вы не используете AndAlso
Концепция скромности имеет в виду перегрузку оператора. в заявлении:
if( A && B){
// do something
}
Сначала оценивается A, если он оценивается как false, B никогда не оценивается. То же самое относится к
if(A || B){
//do something
}
Сначала оценивается A, если он принимает значение true, B никогда не оценивается.
Эта концепция, перегрузка, применяется к (я думаю) всем языкам стиля C и многим другим.
Nopes, по крайней мере, компилятор С# не работает в обратном направлении (в/amp; & или ||). Он слева направо.
Каков хороший пример того, когда использовать побитовый оператор вместо "короткозамкнутого логического"?
Предположим, что у вас есть флаги, скажем, для атрибутов файлов. Предположим, вы определили READ как 4, WRITE as 2 и EXEC как 1. В двоичном формате это:
READ 0100
WRITE 0010
EXEC 0001
Каждый флаг имеет один бит, и каждый из них уникален. Побитовые операторы позволяют объединить эти флаги:
flags = READ & EXEC; // value of flags is 0101
Когда все идет в строке, они выполняются слева направо.
Когда вещи вложены, они выполняются внутри-внешними. Это может показаться запутанным, как обычно, что "самое внутреннее" находится на правой стороне линии, поэтому кажется, что он идет назад...
Например
a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );
Случится так:
GetAddress
с буквальным "Orion"
GetSummary
с буквальным "Orion"
и результатом GetAddress
Foo
с буквальным 5
и результатом GetSummary
a
Мне нравятся ответы Ориона. Я добавлю две вещи:
Скажем, у нас есть следующий пример:
a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
GetSummary("Chris", GetAddress("Chris")));
Здесь порядок выполнения:
GetAddress("Orion")
GetSummary("Orion", ...)
GetAddress("Chris")
GetSummary("Chris", ...)
Foo(...)
a
Я не могу говорить о законных требованиях С# (хотя я уже тестировал аналогичный пример, используя Mono, прежде чем писать этот пост), но этот порядок гарантирован в Java.
И только для полноты (так как это также язык-агностический поток), существуют такие языки, как C и С++, где порядок не гарантируется, если нет точки последовательности. Ссылки: 1, 2. Однако, отвечая на вопрос о потоке, &&
и ||
являются точками последовательности в С++ (если не перегружены, также см. Отличный ответ OJ). Итак, некоторые примеры:
foo() && bar()
foo() & bar()
В случае &&
foo()
гарантируется выполнение до bar()
(если последнее выполняется вообще), так как &&
является точкой последовательности. В случае &
такая гарантия не предоставляется (в C и С++), и действительно bar()
может работать до foo()
или наоборот.
Я где-то слышал, что компиляторы работают назад, но я не уверен, насколько это верно.
Вы используете, и когда вы специально хотите оценить все подвыражения, скорее всего, потому что у них есть побочные эффекты, которые вы хотите, хотя конечный результат будет ложным и, таким образом, не будет выполнять вашу тогдашнюю часть вашего if-statement.
Обратите внимание, что и и | работает как для поразрядных масок, так и для булевых значений и не только для побитовых операций. Они называются поразрядными, но они определены как для целых чисел, так и для булевых типов данных на С#.
В ответ на вопрос, почему или когда кто-нибудь будет использовать And вместо AndAlso (или вместо & &): Вот пример:
if ( x.init() And y.init()) then x.process(y) end y.doDance()
В этом случае я хочу инициализировать как X, так и Y. Y должен быть инициализирован для того, чтобы y.DoDance мог выполнить. Тем не менее, в функции init() я также выполняю некоторые дополнительные действия, такие как проверка сокета, и только если это работает нормально, для обоих я должен идти вперед и выполнять x.process(y).
Я считаю, что это довольно запутанно. Хотя ваш пример работает, это не типичный случай использования And
(и я, вероятно, написал бы это по-другому, чтобы сделать его более понятным). And
(&
в большинстве других языков) на самом деле является побитовой и операции. Вы использовали бы его для вычисления операций с битами, например, для удаления флаговых бит или маскирования и тестирования флаги:
Dim x As Formatting = Formatting.Bold Or Formatting.Italic
If (x And Formatting.Italic) = Formatting.Italic Then
MsgBox("The text will be set in italic.")
End If
Язык программирования D Делает оценка слева направо с коротким замыканием и не позволяет перегрузить операторы &&
и '||'.