Вопрос

В C # (и не стесняйтесь отвечать для других языков), в каком порядке среда выполнения оценивает логический оператор?

Пример:

DataTable myDt = new DataTable();
if (myDt != null && myDt.Rows.Count > 0)
{
    //do some stuff with myDt
}

Какой оператор выполняется во время выполнения в первую очередь -

myDt != null

или:

myDt.Rows.Count > 0

?

Есть ли время, когда компилятор когда-либо оценивал бы оператор в обратном направлении?Возможно, когда задействован оператор "ИЛИ"?


& известен как логический побитовый оператор и всегда будет вычислять все подвыражения

Каков хороший пример того, когда следует использовать побитовый оператор вместо "логического значения с коротким замыканием"?

Это было полезно?

Решение

C# :Слева направо, и обработка останавливается, если найдено несоответствие (принимается значение false).

Другие советы

"С# :Слева направо, и обработка останавливается, если найдено совпадение (оценивается как true)".

Zombie sheep - это неправильно, недостаточно репутации, чтобы проголосовать против этого.

Вопрос касается оператора &&, а не оператора ||.

В случае && оценка будет остановлена, если будет найдено значение FALSE.

В случае || вычисление прекращается, если найдено значение TRUE.

Я понимаю, что на этот вопрос уже был дан ответ, но я хотел бы добавить еще немного информации, относящейся к данной теме.

В языках, таких как C ++, где вы действительно можете перегружать поведение операторов && и ||, настоятельно рекомендуется не делай этого.Это связано с тем, что когда вы перегружаете такое поведение, вы в конечном итоге вынуждаете оценивать обе стороны операции.Это делает две вещи:

  1. Это нарушает механизм отложенного вычисления, потому что перегрузка - это функция, которая должна быть вызвана, и, следовательно, оба параметра оцениваются перед вызовом функции.
  2. Порядок вычисления указанных параметров не гарантируется и может зависеть от компилятора.Следовательно, объекты не будут вести себя так же, как в примерах, перечисленных в вопросе / предыдущих ответах.

Для получения дополнительной информации прочтите книгу Скотта Мейерса, Более эффективный C ++.Ваше здоровье!

vb.net

if( x isNot Nothing AndAlso x.go()) then
  1. Оценка производится слева направо
  2. И кроме того оператор гарантирует, что только в том случае, если левая часть была ИСТИННОЙ, будет оценена правая сторона (очень важно, поскольку ifx - это ничто, x.go приведет к сбою)

Вы можете использовать И вместо и также в 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 (y).

Опять же, это, вероятно, не нужно и не элегантно в 99% случаев, вот почему я сказал, что по умолчанию следует использовать И кроме того.

@shsteimer

Концепция, на которую ссылается скромность, - это перегрузка оператора.в заявлении:...Сначала вычисляется A, если оно принимает значение false, B никогда не вычисляется.То же самое относится и к

Это не перегрузка оператора.Перегрузка оператора - это термин, позволяющий вам определять пользовательское поведение для операторов, таких как *, +, = и так далее.

Это позволило бы вам написать свой собственный класс "Log", а затем выполнить

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
}

Обратите внимание, что существует разница между && и & относительно того, какая часть вашего выражения вычисляется.

&& известен как логическое значение с коротким замыканием AND , и, как отмечали здесь другие, остановится раньше, если результат может быть определен до того, как будут вычислены все подвыражения.

& известен как логический побитовый оператор и всегда будет вычислять все подвыражения.

Как таковой:

if (a() && b())

Будет только звонить b если a ВОЗВРАТ верно.

однако этот:

if (a() & b())

Всегда будет вызывать оба a и b, даже несмотря на то , что результат вызова a является ложным и, следовательно, заведомо ложь независимо от результата вызова b.

Такое же различие существует для операторов || и | .

В некоторых языках бывают интересные ситуации, когда выражения выполняются в другом порядке.Я конкретно думаю о Ruby, но я уверен, что они позаимствовали его откуда-то еще (вероятно, Perl).

Выражения в логике останутся слева направо, но, например,:

puts message unless message.nil?

Приведенное выше действие сначала оценит "message.nil?", затем, если оно примет значение false (если не похоже на if, за исключением того, что оно выполняется, когда условие равно false вместо true), будет выполнено "puts message", которое выводит содержимое переменной message на экран.

Иногда это довольно интересный способ структурирования вашего кода...Лично мне нравится использовать его для очень коротких лайнеров 1, подобных приведенному выше.

Редактировать:

Чтобы было немного понятнее, вышесказанное совпадает с:

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 # не работает в обратном направлении (ни в &&, ни в ||).Это слева направо.

Когда все операции выполняются последовательно, они выполняются слева направо.

Когда объекты вложены, они выполняются от внутреннего к внешнему.Это может показаться запутанным, так как обычно то, что "самое внутреннее" находится с правой стороны строки, поэтому кажется, что все идет в обратном направлении...

Например

a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );

Такие вещи случаются вот так:

  • Звонить GetAddress с буквальным "Orion"
  • Звонить GetSummary с буквальным "Orion" и в результате GetAddress
  • Звонить Foo с буквальным 5 и в результате GetSummary
  • Присвоите это значение a

Мне нравятся ответы Ориона.Я добавлю две вещи:

  1. Принцип "слева направо" по-прежнему применяется в первую очередь
  2. Переход от внутреннего к внешнему, чтобы убедиться, что все аргументы разрешены перед вызовом функции

Допустим, у нас есть следующий пример:

a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
           GetSummary("Chris", GetAddress("Chris")));

Вот порядок выполнения:

  1. GetAddress("Orion")
  2. GetSummary("Orion", ...)
  3. GetAddress("Chris")
  4. GetSummary("Chris", ...)
  5. Foo(...)
  6. Присваивает a

Я не могу говорить о юридических требованиях C # (хотя я тестировал аналогичный пример с использованием Mono перед написанием этого поста), но этот порядок гарантирован в Java.

И просто для полноты картины (поскольку это также не зависящий от языка поток), существуют такие языки, как C и C ++, где порядок не гарантируется, если нет точки последовательности.Ссылки: 1, 2.Однако, отвечая на вопрос темы,, && и || являются точками последовательности в C ++ (если не перегружены;также смотрите отличный ответ OJ).Итак, несколько примеров:

  • foo() && bar()
  • foo() & bar()

В && кейс, foo() гарантированно запускается раньше bar() (если последнее вообще выполняется), поскольку && является точкой последовательности.В & случае, такая гарантия не дается (в C и C++), и действительно bar() может запуститься раньше foo(), или наоборот.

Каков хороший пример того, когда следует использовать побитовый оператор вместо "логического значения с коротким замыканием"?

Предположим, у вас есть флаги, скажем, для атрибутов файла.Предположим, вы определили READ как 4, WRITE как 2, а EXEC как 1.В двоичном формате это:

READ  0100  
WRITE 0010  
EXEC  0001

Каждый флаг имеет один набор битов, и каждый из них уникален.Побитовые операторы позволяют вам комбинировать эти флаги:

flags = READ & EXEC; // value of flags is 0101

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

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

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

@csmba:

В последующем был задан вопрос, почему и когда кто-либо будет использовать 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 (& в большинстве других языков) на самом деле является побитовой операцией-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 Действительно выполняет оценка слева направо с коротким замыканием и не делает разрешить перегрузку && и '||' операторы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top