Lub w porównaniu z OrElse


96

Jaka jest różnica między or i OrElse ?

if temp is dbnull.value or temp = 0

powoduje błąd:

Operator „=” nie jest zdefiniowany dla typu „DBNull” i typu „Integer”.

podczas gdy ten działa jak urok !?

if temp is dbnull.value OrElse temp = 0

Odpowiedzi:


147

OrElsejest operatorem zwarcia , Ornie jest.

Zgodnie z definicją operatora logicznego „or”, jeśli pierwszy człon jest True, to całość jest zdecydowanie prawdziwa - więc nie musimy oceniać drugiego członu.

OrElsewie o tym, więc nie próbuje tego oceniać, temp = 0kiedy już to ustaliłtemp Is DBNull.Value

Ornie wie o tym i zawsze będzie próbował ocenić oba terminy. Kiedy temp Is DBNull.Valuenie można go porównać do zera, więc się przewraca.

Powinieneś użyć ... cóż, cokolwiek ma sens.


2
Więc czy ma sens tylko wtedy, gdy wywołuję funkcję po lub, która ma efekty uboczne, od których zależy mój kod?
Ralph M. Rickenbach

4
Lub ma sens we wszystkich przypadkach, w których druga pozycja nie wywołuje błędu, jeśli pierwsza jest prawdziwa ...
awe

4
@ malach: Przypuszczam, że tak (w większości innych języków naprawdę otrzymujesz zachowanie OrElse): Nie jest dobrym pomysłem wywoływanie funkcji z efektami ubocznymi w złożonych warunkach warunkowych, przez co kod jest nieczytelny.
Utaal

4
@ awe: tak, ale dlaczego w ogóle chcesz tracić czas na ocenianie czegoś, co z definicji nie zmieni wyniku wyrażenia?
Utaal

3
@MarkJ: Nie sądzę, aby cztery dodatkowe znaki zakłócały czytelność. Z drugiej strony użycie operatora, który zależy od istnienia efektów ubocznych (jak napisał malach), aby był znaczący, brzmi jak zły pomysł (i może utrudnić czytelność!). Efekty uboczne w takich miejscach uznałbym za duże nie-nie i nie potrafię wymyślić żadnych sytuacji, w których wolałbym „Or” od „OrElse”. Szkoda, że ​​te operatory działają w ten sposób, ponieważ zachowanie „OrElse” jest prawdopodobnie tym, czego większość oczekuje, nawet przy użyciu „Or” (zwłaszcza jeśli pochodzi z innych języków).
Kjartan

43

Jest to takie samo zachowanie, jak w przypadku C #, gdzie wszyscy używają Coditional Or (||) i Conditional And (&&), gdzie masz również normalne Or (|) i normalne And (&). Porównanie C # z VB.Net to:

| => Lub

|| => OrElse

& => I

&& => I także

Condifitonal boolowskie operatory są bardzo przydatne w zapobieganiu zagnieżdżaniu konstrukcji if. Ale czasami potrzebne są normalne operatory boolowskie, aby zapewnić trafienie w obie ścieżki kodu.


9
Nigdy nie wiedziałem, że to jest dostępne. Dzięki za nowe informacje. Dobrze wiedzieć, chociaż tak naprawdę nie widzę żadnej sytuacji, w której chciałbym użyć "|". Myślę, że wymagałoby to drugiego warunku, aby wywołać skutki uboczne, aby mieć jakikolwiek sens, a to samo w sobie nie ma moim zdaniem sensu! ;)
Kjartan

8
Ech, o ile wiem, |i &są operatorami bitowymi w C #, a nie operacjami logicznymi.
Nyerguds

8

OrElse jest zwarte , co oznacza, że ​​tylko jedna strona wyrażenia zostanie przetestowana, jeśli pierwsza strona jest zgodna.

Podobnie jak AndAlso przetestuje tylko jedną stronę wyrażenia, jeśli pierwsza połowa zakończy się niepowodzeniem.


4

(Spojrzałem na inne odpowiedzi i zdałem sobie sprawę, że bardzo się myliłem)

Operator OrElse "wykonuje skracającą logiczną dysjunkcję na dwóch wyrażeniach", to znaczy: jeśli lewy operand jest prawdziwy, a więc całe wyrażenie jest gwarantowane, prawy operand nie będzie nawet oceniany (jest to przydatne w przypadki takie jak:

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

aby uniknąć rzutu NullReferenceException przez operand po prawej stronie.

Jestem szczerze zdumiony, że ta ( leniwa ocena ) nie jest domyślnym zachowaniem ori andtak jak jest w C / C ++ i C # (i wielu innych językach ...)


7
Rzecz w tym, że w klasycznym VB było tylko And i Or, które nie powodowały zwarcia. Myślę , że mam rację, mówiąc, że pierwsze wersje beta VB.NET faktycznie zmieniły zachowanie tych operatorów - było zamieszanie, więc zostały one zmienione z powrotem i wprowadzono AndAlso i OrElse (zwarcie). Mogę sobie tylko wyobrazić alternatywne nazwy, które musieli wziąć pod uwagę, gdyby były to te, które były najlepsze ...
AakashM

1
Zapewniając Or i OrElse (| i || w C #) pozwala to deweloperowi wybrać sposób obsługi własnego kodu. Korzystając z powyższego kodu, musiałbym użyć wokół niego try catch, aby obsłużyć wartość null w zmiennej a. OrElse pozwala programiście obsłużyć to w instrukcji else jako znany możliwy wynik, a nie jako wyjątek. Jest to bardziej oczywiste, jeśli zmienna a była parametrem w metodzie, w której masz mniejszą kontrolę nad tym, kiedy zmiennej przypisywana jest wartość (tj. Poza metodą)
Kevin Hogg

Zwarcie nie jest domyślnym zachowaniem operacji OR i AND w języku c #. c # ma dwa różne operatory dla operacji bitowych i logicznych / zwarciowych. && i || wykonać porównania logiczne i zwrócić wartość logiczną The & i | operatory są bitowe i zwracają wartość całkowitą. Więc gdzie 1 || 2 zwraca „prawda”, 1 | 2 zwraca „3”.
TomXP411

4

OrElse ocenia pierwsze wyrażenie, a następnie, jeśli jest prawdziwe, przejdzie do instrukcji, podczas gdy OR ocenia dwa wyrażenia, zanim przejdzie do ich instrukcji.

Przykład:

Textbox1.Text= 4

Textbox2.Text= ""

Korzystanie z OrElse

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

Wynik to: PRAWDA


Korzystanie z OR

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

            MsgBox("True")
  End If

Wynik: błąd nie może przekonwertować ciągu na podwójny.


3

Odpowiedź Berta nie jest zbyt dokładna. „|” lub „&” jest operatorem logicznym, w C # zawsze traktuje go jako operator bitowy, zobacz poniższy kod jako przykład

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

Poniżej znajduje się 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

kiedy używasz || aby przetestować "a == null" i "a.ToString () ==" sdffd ", IL będzie

 .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

Teraz widzisz różnicę, proszę nie myśl '|' lub „and” jako operator warunkowy, to tylko operator logiczny, nie sądzę, aby było konieczne używanie go do oceny stanu


2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. W to też wierzyłem, dopóki nie zobaczyłem tego odniesienia, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
user3207158

Twoja odpowiedź jest wyrwana z kontekstu. Pytanie nie dotyczy C #, ale raczej VB, gdzie cztery operatory logiczne: And, AndAlso, Or, OrElse, Not i Xor są operatorami logicznymi i bitowymi.
Jean-François

0

O ile logika twojego kodu nie wymaga zachowania zwarciowego zapewnianego przez OrElse, skłaniałbym się do użycia operatora Or, ponieważ:

  • Używanie „Lub” jest proste i wymaga mniej pisania.
  • W większości przypadków oszczędności czasu obliczeniowego wynikające z używania OrElse są pomijalne.
  • Co najważniejsze, użycie OrElse może ukryć błędy w późniejszych klauzulach, które mogą nie zostać początkowo ujawnione, dopóki te warunki nie zostaną ostatecznie spełnione przez logikę programu.

0

Przyczyną niepowodzenia kompilacji w tym przykładzie jest kolejność operacji.

Parser wyrażeń próbuje najpierw ocenić „dbnull.value lub temp”.

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

Błąd występuje tutaj, ponieważ nie można wykonać bitowego OR między liczbą całkowitą (temp) a wartością dbnull.value.

OrElse rozwiązuje ten problem, nie dlatego, że jest zwarty, ale dlatego, że jest niższy w kolejności operacji , więc najpierw są oceniane „temp is dbnull.value” i „3 = 0”, a nie parser próbuje porównać dbNull i temp.

Więc ocena z OrElse działa tak, jak się spodziewasz: (zakładając 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

To był egzamin wstępny w firmie programistycznej, dla której pracowałem, i był to częsty problem, z którym miałem do czynienia w VB6. Dlatego dobrym pomysłem jest umieszczanie wyrażeń podrzędnych w nawiasach, gdy używasz operatorów boolowskich:

Skompilowałoby się to poprawnie:

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

Chociaż, jak wszyscy już zauważyli, OrElse i AndAlso są naprawdę właściwymi operatorami do użycia w tym kontekście.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.