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

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

Пример:

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

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

myDt != null

или же:

myDt.Rows.Count > 0

?

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


& is known as a logical bitwise operator and will always evaluate all the sub-expressions

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
0
3 580
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

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

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

Ответ принят как подходящий

C#: слева направо, и обработка останавливается, если обнаружено несоответствие (оценивается как ложное).

Как заявляли другие, замыкание на оператор && происходит на ложный.

Broam 13.04.2010 22:26

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

vb.net

if ( x isNot Nothing AndAlso x.go()) then
  1. Оценка выполняется слева направо
  2. Оператор А также гарантирует, что только если левая сторона была ИСТИНА, правая сторона будет оценена (очень важно, поскольку если x - ничего, 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 (y).

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

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

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

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

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

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

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

ZombieSheep беспощаден. Единственный "подводный камень", который может подождать, - это то, что это верно только в том случае, если вы используете оператор &&. При использовании оператора & оба выражения будут оцениваться каждый раз, независимо от того, оценивается ли одно или оба как ложные.

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())

Будет вызывать б, только если а возвращает истинный.

однако это:

if (a() & b())

Всегда будет вызывать как а, так и б, даже если результат вызова а ложен и, следовательно, известен как ложный, независимо от результата вызова б.

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

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

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

puts message unless message.nil?

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

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

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

Чтобы было немного понятнее, приведенное выше то же самое, что:

unless message.nil?
  puts message
end

Нет, по крайней мере, компилятор C# не работает в обратном направлении (в && или ||). Это слева направо.

What is a good example of when to use the bitwise operator instead of the "short-circuited boolean"?

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

READ  0100  
WRITE 0010  
EXEC  0001

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

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

@shsteimer

The concept modesty is referring to is operator overloading. in the statement: ... A is evaluated first, if it evaluates to false, B is never evaluated. The same applies to

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

Это позволит вам написать свой собственный класс «Журнал», а затем выполнить

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

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

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

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

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

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

Например

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

Бывает так:

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

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

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

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

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

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

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

«C#: слева направо, и обработка останавливается, если найдено совпадение (истинно)».

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

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

В случае && оценка остановится, если будет найдено ЛОЖЬ.

В случае || оценка останавливается, если обнаруживается ИСТИНА.

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

ZombieSheep 20.08.2008 11:15

@csmba:

It was asked in a followup why or when would anyone use And instead of AndAlso (or & instead of &&): Here is an example:

if ( x.init() And y.init()) then
   x.process(y)
end 
y.doDance()

In this case, I want to init both X and Y. Y must be initialized in order for y.DoDance to be able to execute. However, in the init() function I am doing also some extra thing like checking a socket is open, and only if that works out ok, for both, I should go ahead and do the 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 позволяет оценка слева направо с коротким замыканием и не допускать перегрузку операторов && и "||".

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