Или против OrElse

83

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

if temp is dbnull.value or temp = 0

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

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

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

if temp is dbnull.value OrElse temp = 0
Теги:

8 ответов

134
Лучший ответ

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

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

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

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

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

  • 2
    Так Или имеет смысл только тогда, когда я вызываю функцию после или у которой есть побочные эффекты, от которых зависит мой код?
  • 2
    Или имеет смысл во всех случаях, когда второй элемент не вызывает ошибку, если первый является истинным ...
Показать ещё 7 комментариев
36

Это то же самое, что и с С#, где каждый использует Coditional Or (||) и Conditional And (&), где у вас также есть нормальный Or (|) и обычный And (&), Таким образом, сравнение С# с VB.Net:

| = > Или

|| = > OrElse

& = > И

& & = > AndAlso

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

  • 6
    Я никогда не знал, что это было доступно. Спасибо за новую информацию. Полезно знать, хотя я не вижу ситуации, в которой я хотел бы использовать «|». Я думаю, что для того, чтобы побочные эффекты имели какой-либо смысл, потребовалось бы второе условие, и это само по себе не имеет большого смысла, по моему мнению! ;)
  • 4
    Эх, насколько я знаю, | и & являются побитовыми операторами в C #, а не булевыми операциями вообще.
8

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

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

4

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

        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

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

  • 2
    The '|' or '&' is logical operator, in C #, it always treat as bit operator . Я тоже в это верил, пока не увидел эту ссылку, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
4

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

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

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

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

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

  • 7
    Дело в том, что в VB classic были только And и Or, которые не были короткозамкнутыми. Я думаю, что я прав, говоря, что первые бета-версии VB.NET фактически изменили поведение этих операторов - произошел шум, поэтому они были изменены обратно, и были введены AndAlso и OrElse (короткое замыкание). Я могу только представить альтернативные имена, которые они должны были рассмотреть, если бы они были лучшими ...
  • 1
    Предоставляя Or и OrElse (| и || в C #), это позволяет разработчику выбирать, как они обрабатывают свой собственный код. Используя приведенный выше код, мне пришлось бы использовать метод catch для его обработки нулевого значения в переменной a. OrElse позволяет разработчику обрабатывать это в остальной части оператора if как известный возможный результат, а не как исключение. Это более очевидно, если переменная a была параметром в методе, где у вас меньше контроля, когда переменной присваивается значение (т. Е. Вне метода)
Показать ещё 1 комментарий
3

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

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

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 действительно правильные операторы для использования в этом контексте.

0

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню