С# логический порядок и поведение компилятора

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

Пример:

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

Какой оператор оценивает среду выполнения -

myDt != null

или

myDt.Rows.Count > 0

?

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


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

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

Ответы

Ответ 1

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

Ответ 2

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

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

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

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

В случае || оценка останавливается, если найден TRUE.

Ответ 3

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

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

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

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

Ответ 4

vb.net

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

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

Ответ 5

@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

на самом деле называется Оценка короткого замыкания

Ответ 6

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
}

Ответ 7

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

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

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

Таким образом:

if (a() && b())

Будет вызывать только b, если a возвращает true.

однако это:

if (a() & b())

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

Эта же разница существует для || и | операторы.

Ответ 8

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

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

puts message unless message.nil?

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

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

Edit:

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

unless message.nil?
  puts message
end

Ответ 9

Левый, затем останавливается, если он равен нулю.

Изменить: В vb.net он будет оценивать обе и, возможно, выбросить ошибку, если вы не используете AndAlso

Ответ 10

Концепция скромности имеет в виду перегрузку оператора. в заявлении:

if( A && B){
    // do something
}

Сначала оценивается A, если он оценивается как false, B никогда не оценивается. То же самое относится к

if(A || B){
    //do something
}

Сначала оценивается A, если он принимает значение true, B никогда не оценивается.

Эта концепция, перегрузка, применяется к (я думаю) всем языкам стиля C и многим другим.

Ответ 11

Nopes, по крайней мере, компилятор С# не работает в обратном направлении (в/amp; & или ||). Он слева направо.

Ответ 12

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

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

READ  0100  
WRITE 0010  
EXEC  0001

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

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

Ответ 13

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

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

Например

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

Случится так:

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

Ответ 14

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

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

Скажем, у нас есть следующий пример:

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() или наоборот.

Ответ 15

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

Ответ 16

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

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

Ответ 17

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

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