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

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

Пример:

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

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

myDt != null

или:

myDt.Rows.Count > 0

?

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


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

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

7.08.2008 20:30:00
18 ОТВЕТОВ
РЕШЕНИЕ

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

16
14.04.2010 16:41:33
Как уже говорили другие, короткое замыкание на && оператор происходит на false .
Broam 13.04.2010 18:26:12

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

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

2
7.08.2008 20:31:32

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

0
7.08.2008 20:34:11

vb.net

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

Вы можете использовать А вместо And также в vb. в этом случае левая сторона также оценивается первой, но правая будет оцениваться независимо от результата.

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


В последующем спросили, почему или когда кто-то будет использовать А вместо AndAlso (или & вместо &&): Вот пример:

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

В этом случае я хочу инициализировать оба X и Y. Y должен быть инициализирован, чтобы y.DoDance мог выполняться. Тем не менее, в функции init () я также делаю некоторые дополнительные вещи, такие как проверка, открыт ли сокет, и только если это работает нормально, для обоих я должен пойти дальше и выполнить x.process (y).

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

6
7.08.2008 23:32:40

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

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

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

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

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

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

2
7.08.2008 20:35:32

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
}
4
7.08.2008 20:45:43

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

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

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

В качестве таких:

if (a() && b())

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

однако это:

if (a() & b())

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

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

4
7.08.2008 20:52:27

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

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

puts message unless message.nil?

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

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

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

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

unless message.nil?
  puts message
end
4
7.08.2008 21:27:11

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

1
7.08.2008 21:00:27

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

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

READ  0100  
WRITE 0010  
EXEC  0001

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

flags = READ & EXEC; // value of flags is 0101
1
8.08.2008 14:05:12

@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

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

5
7.08.2008 21:58:21

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

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

0
7.08.2008 22:01:24

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

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

Например

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

Вещи случаются так:

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

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

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

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

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

8
7.08.2008 22:23:56

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

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

1
7.08.2008 22:33:16

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

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

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

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

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

9
8.08.2008 06:51:14
Ага. Ты совершенно прав. Я надеюсь, что мой первоначальный ответ был истолкован правильно. Я не собирался вводить кого-либо в заблуждение.
ZombieSheep 20.08.2008 07:15:58

@csmba :

В последующем спросили, почему или когда кто-то будет использовать А вместо 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
0
23.05.2017 12:17:20

Язык программирования D Выполняет оценку слева направо с коротким замыканием и не допускает перегрузки &&и | || операторы.

0
23.05.2017 12:09:33