Сведения о вопросе

rjevskii

16:03, 1st July, 2020

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

Просмотров: 550   Ответов: 18

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

Пример:

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

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

myDt != null

или:

myDt.Rows.Count > 0
?

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


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

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



  Сведения об ответе

nYU

18:03, 1st July, 2020

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


  Сведения об ответе

FAriza

18:03, 1st July, 2020

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

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

Вопрос заключается в операторе &&, а не в операторе||.

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

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


  Сведения об ответе

lool

18:03, 1st July, 2020

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

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

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

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


  Сведения об ответе

nYU

18:03, 1st July, 2020

vb.net

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

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


  Сведения об ответе

+-*/

18:03, 1st July, 2020

@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

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


  Сведения об ответе

darknet

18:03, 1st July, 2020

ZombieSheep находится в тупике. Единственное, что может ожидать "gotcha", это то, что это верно только в том случае, если вы используете оператор &&. При использовании оператора & оба выражения будут вычисляться каждый раз, независимо от того, является ли одно или оба значения равными 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
}


  Сведения об ответе

dump

18:03, 1st July, 2020

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

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

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

По существу:

if (a() && b())

Вызовет только b , Если a возвращает true .

тем не менее, это:

if (a() & b())

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

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


  Сведения об ответе

lesha

18:03, 1st July, 2020

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

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

puts message unless message.nil?

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

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

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

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

unless message.nil?
  puts message
end


  Сведения об ответе

LIZA

18:03, 1st July, 2020

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

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


  Сведения об ответе

screen

18:03, 1st July, 2020

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

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

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

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

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

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


  Сведения об ответе

VCe znayu

18:03, 1st July, 2020

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


  Сведения об ответе

Chhiki

18:03, 1st July, 2020

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

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

READ  0100  
WRITE 0010  
EXEC  0001

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

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


  Сведения об ответе

lool

18:03, 1st July, 2020

Когда все идет по плану, они исполняются left-to-right.

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

Например

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

Все происходит вот так:

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


  Сведения об ответе

COOL

18:03, 1st July, 2020

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

  1. left-to-right все еще применяется в первую очередь
  2. В inner-to-outer, чтобы убедиться, что все аргументы вычисляются до вызова функции

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

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#'s (хотя я тестировал аналогичный пример с использованием Mono перед написанием этого поста), но этот порядок гарантирован в Java.

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

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

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


  Сведения об ответе

SEEYOU

18:03, 1st July, 2020

Язык программирования D действительно делает оценку left-to-right с коротким замыканием и не допускает перегрузки операторов && и '||' .


  Сведения об ответе

lesha

18:03, 1st July, 2020

@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


  Сведения об ответе

fo_I_K

18:03, 1st July, 2020

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


  Сведения об ответе

PAGE

18:03, 1st July, 2020

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться