Или против OrElse

96

В чем разница между or и OrElse ?

if temp is dbnull.value or temp = 0

выдает ошибку:

Оператор '=' не определен для типа DBNull и типа Integer.

а этот работает как шарм !?

if temp is dbnull.value OrElse temp = 0
OrElse
источник

Ответы:

147

OrElseявляется короткозамкнутым оператором, Orне является.

По определению логического оператора «или», если первый член истинен, тогда все определенно истинно, поэтому нам не нужно оценивать второй член.

OrElseзнает это, поэтому не пытается оценить, как temp = 0только выяснится, чтоtemp Is DBNull.Value

Orне знает этого и всегда будет пытаться оценить оба термина. Когда temp Is DBNull.Value, его нельзя сравнивать с нулем, поэтому он падает.

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

АакашМ
источник
2
Итак, Или имеет смысл только тогда, когда я вызываю функцию после того, как или у которой есть побочные эффекты, от которых зависит мой код?
Ральф М. Рикенбах
4
Или имеет смысл во всех случаях, когда второй элемент не вызывает ошибки, если первый верен ...
awe
4
@ malach: Я полагаю, что да (вы действительно получаете поведение OrElse по умолчанию на большинстве других языков): не рекомендуется вызывать функции с побочными эффектами в составных условных выражениях, это делает код нечитаемым.
Utaal
4
@ awe: да, но зачем тратить время на оценку чего-то, что по определению не изменит результат выражения?
Utaal
3
@MarkJ: Я не думаю, что четыре лишних символа мешают читаемости. С другой стороны, использование оператора, который зависит от наличия побочных эффектов (как писал Малах), звучит как плохая идея (и может усложнить читаемость!). Я бы считал побочные эффекты в таких местах большим запретом и не могу придумать никаких ситуаций, в которых я бы предпочел «Или», а не «OrElse». Жаль, что эти операторы работают таким образом, поскольку поведение «OrElse», вероятно, является тем, чего большинство ожидает даже при использовании «Или» (особенно при переходе с других языков).
Kjartan
43

Это то же поведение, что и в C #, где все используют Coditional Or (||) и Условное And (&&), где у вас также есть нормальное Or (|) и нормальное And (&). Итак, сравнение C # с VB.Net:

| => Или

|| => OrElse

& => И

&& => И еще

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

Берт Хисбин
источник
9
Я никогда не знал, что это доступно. Спасибо за новую информацию. Полезно знать, хотя я действительно не вижу ситуации, в которой я бы хотел использовать "|". Я думаю, что для возникновения побочных эффектов потребуется второе условие, а это само по себе, на мой взгляд, не имеет особого смысла! ;)
Kjartan
8
Эх, насколько я знаю, |и &в C # это побитовые операторы, а не логические операции вообще.
Nyerguds 05
8

OrElse закорочен , это означает, что только одна сторона выражения будет проверена, если первая сторона совпадает.

Так же, как AndAlso будет проверять только одну сторону выражения, если первая половина не удалась.

Стивипвелл
источник
4

(Я просмотрел другие ответы и понял, что ужасно ошибался)

Оператор OrElse «выполняет короткое логическое разделение двух выражений», то есть: если левый операнд истинен и поэтому все выражение гарантированно истинно, правый операнд даже не будет оцениваться (это полезно в случаи как:

string a;
//...
if (a is null) or (a = "Hi") //...

чтобы избежать выброса исключения NullReferenceException правым операндом.

Я искренне удивляло , что это ( ленивая оценка ) не является поведением по умолчанию orи , andкак в C / C ++ и C # (и многие другие языки ...)

Утаал
источник
7
Дело в том, что в VB classic были только And и Or, которые не замыкались. Я думаю, что я прав, говоря, что первые бета-версии VB.NET фактически изменили поведение этих операторов - поднялся шум, поэтому они были изменены обратно, и были введены AndAlso и OrElse (короткое замыкание). Я могу только вообразить альтернативные имена, которые они должны были бы рассмотреть, если бы они были лучшими ...
AakashM
1
Предоставляя Or и OrElse (| и || в C #), это позволяет разработчику выбирать, как им обрабатывать свой собственный код. Используя приведенный выше код, мне пришлось бы попытаться обойти его, чтобы обработать нулевое значение в переменной a. OrElse позволяет разработчику обрабатывать это в else оператора if как известный возможный результат, а не исключение. Это более очевидно, если переменная a была параметром в методе, где у вас меньше контроля над тем, когда переменной присваивается значение (т.е. вне метода),
Кевин Хогг,
Короткое замыкание также не является поведением OR и AND по умолчанию в C #. В c # есть два разных оператора для побитовых операций и операций логического / короткого замыкания. && и || выполнять логические сравнения и возвращать логическое значение & и | операторы побитовые и возвращают целочисленное значение. Итак, где 1 || 2 возвращает «истину», 1 | 2 возвращает «3».
TomXP411
4

OrElse оценивает первое выражение, затем, если оно истинно, оно переходит к оператору, а OR оценивает два выражения, прежде чем перейти к их оператору.

Пример:

Textbox1.Text= 4

Textbox2.Text= ""

Использование OrElse

  If TextBox1.Text > 2 OrElse TextBox2.Text > 3 Then
      MsgBox("True")
  End If

Результат: ИСТИНА


Использование OR

 If TextBox1.Text > 2 Or TextBox2.Text > 3 Then

            MsgBox("True")
  End If

Результат: Ошибка не может преобразовать строку в двойную.

Ларц
источник
3

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

        static void Main()
        {
            object a = null;
            int b = 3;
            if (a == null | a.ToString() == "sdffd")
            {
                Console.WriteLine("dddd");
            }
            Console.WriteLine(b | b);
            Console.Read();
        }

Следующее - IL

    .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       62 (0x3e)
  .maxstack  3
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
   IL_0000:  nop
   IL_0001:  ldnull
   IL_0002:  stloc.0
   IL_0003:  ldc.i4.3
   IL_0004:  stloc.1
   IL_0005:  ldloc.0
   IL_0006:  ldnull
   IL_0007:  ceq
   IL_0009:  ldloc.0
   IL_000a:  callvirt   instance string [mscorlib]System.Object::ToString()
   IL_000f:  ldstr      "sdffd"
   IL_0014:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
   IL_0019:  or
   IL_001a:  ldc.i4.0
   IL_001b:  ceq
   IL_001d:  stloc.2
   IL_001e:  ldloc.2
   IL_001f:  brtrue.s   IL_002e
   IL_0021:  nop
   IL_0022:  ldstr      "dddd"
   IL_0027:  call       void [mscorlib]System.Console::WriteLine(string)
   IL_002c:  nop
   IL_002d:  nop
   IL_002e:  ldloc.1
   IL_002f:  ldloc.1
   IL_0030:  or
   IL_0031:  call       void [mscorlib]System.Console::WriteLine(int32)
   IL_0036:  nop
   IL_0037:  call       int32 [mscorlib]System.Console::Read()
   IL_003c:  pop
   IL_003d:  ret
    } // end of method Program::Main

когда вы используете || для проверки "a == null" и "a.ToString () ==" sdffd "IL будет

 .method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       63 (0x3f)
  .maxstack  2
  .locals init ([0] object a,
           [1] int32 b,
           [2] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldc.i4.3
  IL_0004:  stloc.1
  IL_0005:  ldloc.0
  IL_0006:  brfalse.s  IL_001d
  IL_0008:  ldloc.0
  IL_0009:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_000e:  ldstr      "sdffd"
  IL_0013:  call       bool [mscorlib]System.String::op_Equality(string,
                                                                 string)
  IL_0018:  ldc.i4.0
  IL_0019:  ceq
  IL_001b:  br.s       IL_001e
  IL_001d:  ldc.i4.0
  IL_001e:  stloc.2
  IL_001f:  ldloc.2
  IL_0020:  brtrue.s   IL_002f
  IL_0022:  nop
  IL_0023:  ldstr      "dddd"
  IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_002d:  nop
  IL_002e:  nop
  IL_002f:  ldloc.1
  IL_0030:  ldloc.1
  IL_0031:  or
  IL_0032:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0037:  nop
  IL_0038:  call       int32 [mscorlib]System.Console::Read()
  IL_003d:  pop
  IL_003e:  ret
} // end of method Program::Main

Теперь вы видите разницу, пожалуйста, не думайте о "|" или 'и' как условный оператор, это просто логический оператор, я не думаю, что его нужно использовать для оценки условия

FrankX
источник
2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. Я тоже верил в это, пока не увидел эту ссылку, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
user3207158
Ваш ответ вне контекста. Вопрос не относится к C #, а скорее к VB, где четыре логических оператора: And, AndAlso, Or, OrElse, Not и Xor являются логическими и побитовыми операторами.
Жан-Франсуа
0

Если ваша логика кода не требует поведения короткого замыкания, которое обеспечивает OrElse, я бы склонился к использованию оператора Or, потому что:

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

Причина сбоя компиляции в этом примере - это порядок операций.

Синтаксический анализатор выражений сначала пытается вычислить "dbnull.value или temp".

if temp is (dbnull.value or temp) = 0

Ошибка здесь, потому что вы не можете выполнить побитовое ИЛИ между целым числом (temp) и dbnull.value.

OrElse исправляет это не потому, что он закорочен, а потому, что он ниже по порядку операций , и поэтому сначала оцениваются «temp is dbnull.value» и «3 = 0», а не анализатор, пытающийся сравнить dbNull и темп.

Таким образом, оценка с помощью OrElse работает так, как вы ожидаете: (предположим, что temp = 3)

if temp is dbnull.value OrElse temp = 0 then
if 3 is dbnull.value OrElse 3 = 0 then
if false OrElse 3=0 then
if false OrElse false then
if false then

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

Это было бы правильно скомпилировано:

if (temp is dbnull.value) Or (temp = 0) then 

Хотя, как все уже отметили, OrElse и AndAlso действительно являются правильными операторами для использования в этом контексте.

TomXP411
источник