Oder gegen OrElse

94

Was ist der Unterschied zwischen oder und OrElse ?

if temp is dbnull.value or temp = 0

erzeugt den Fehler:

Der Operator '=' ist nicht für den Typ 'DBNull' und den Typ 'Integer' definiert.

während dieser wie ein Zauber wirkt!?

if temp is dbnull.value OrElse temp = 0
Oder Else
quelle

Antworten:

144

OrElseist ein Kurzschlussbetreiber , Ornicht.

Nach der Definition des booleschen Operators 'oder' ist das Ganze definitiv wahr, wenn der erste Term True ist - wir müssen also den zweiten Term nicht bewerten.

OrElseweiß das, also versuche nicht zu bewerten, temp = 0sobald es das festgestellt hattemp Is DBNull.Value

Orweiß das nicht und wird immer versuchen, beide Begriffe zu bewerten. Wenn temp Is DBNull.Valuees nicht mit Null verglichen werden kann, fällt es um.

Sie sollten verwenden ... nun, je nachdem, was sinnvoll ist.

AakashM
quelle
2
Also oder macht es nur Sinn, wenn ich eine Funktion aufrufe, nachdem die oder die Nebenwirkungen hat, von denen mein Code abhängt?
Ralph M. Rickenbach
4
Oder macht Sinn in allen Fällen, in denen das zweite Element keinen Fehler auslöst, wenn das erste wahr ist ...
Ehrfurcht
4
@ malach: Ich nehme an (in den meisten anderen Sprachen ist das OrElse-Verhalten standardmäßig verfügbar): Es ist keine gute Idee, Funktionen mit Nebenwirkungen in zusammengesetzten Bedingungen aufzurufen, da dies den Code unlesbar macht.
Utaal
4
@ awe: Ja, aber warum willst du überhaupt Zeit damit verschwenden, etwas zu bewerten, das per Definition das Ergebnis des Ausdrucks nicht ändert?
Utaal
3
@ MarkJ: Ich glaube nicht, dass vier zusätzliche Zeichen die Lesbarkeit stören. Auf der anderen Seite klingt die Verwendung eines Operators, der von der Existenz von Nebenwirkungen abhängt (wie Malach schrieb), um sinnvoll zu sein, nach einer schlechten Idee (und kann die Lesbarkeit erschweren!). Ich würde Nebenwirkungen an solchen Orten als ein großes Nein-Nein betrachten und kann mir keine Situationen vorstellen, in denen ich "Oder" gegenüber "OrElse" bevorzugen würde. Es ist schade, dass diese Operatoren auf diese Weise funktionieren, da das "OrElse" -Verhalten wahrscheinlich das ist, was die meisten erwarten, selbst wenn sie "Or" verwenden (insbesondere wenn sie aus anderen Sprachen stammen).
Kjartan
42

Dies ist das gleiche Verhalten wie bei C #, wo jeder das Coditional Or (||) und das Conditional And (&&) verwendet, wobei Sie auch das normale Or (|) und das normale And (&) haben. Der Vergleich von C # mit VB.Net lautet also:

| => Or. En

|| => OrElse

& => Und

&& => AndAlso

Die bedingten booleschen Operatoren sind sehr nützlich, um verschachtelte if-Konstruktionen zu verhindern. Manchmal werden jedoch die normalen booleschen Operatoren benötigt, um sicherzustellen, dass beide Codepfade getroffen werden.

Bert Heesbeen
quelle
9
Ich wusste nie, dass dies verfügbar ist. Vielen Dank für neue Informationen. Gut zu wissen, obwohl ich keine Situation sehen kann, in der ich "|" verwenden möchte. Ich denke, es würde die zweite Bedingung erfordern, um Nebenwirkungen zu verursachen, die irgendeinen Sinn ergeben, und das an sich macht meiner Meinung nach wenig Sinn! ;)
Kjartan
7
Eh, soweit ich weiß, |und &sind bitweise Operatoren in C #, überhaupt keine booleschen Operationen.
Nyerguds
8

OrElse ist kurzgeschlossen . Dies bedeutet, dass nur eine Seite des Ausdrucks getestet wird, wenn die erste Seite übereinstimmt.

Genau wie AndAlso wird nur eine Seite des Ausdrucks getestet, wenn die erste Hälfte fehlschlägt.

stevehipwell
quelle
4

(Ich habe mir andere Antworten angesehen und festgestellt, dass ich mich schrecklich geirrt habe.)

Der OrElse-Operator "führt eine logische Kurzschluss-Disjunktion für zwei Ausdrücke durch", dh: Wenn der linke Operand wahr ist und somit garantiert wird, dass der gesamte Ausdruck wahr ist, wird der rechte Operand nicht einmal ausgewertet (dies ist nützlich in Fälle wie:

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

um einen NullReferenceException-Wurf durch den rechten Operanden zu vermeiden.

Ich bin aufrichtig erstaunt, dass dies ( verzögerte Auswertung ) nicht das Standardverhalten von orund andwie in C / C ++ und C # (und vielen anderen Sprachen ...) ist.

Utaal
quelle
7
Die Sache ist, in VB classic gab es nur And und Or, die nicht kurzgeschlossen waren. Ich glaube, ich habe Recht, wenn ich sage, dass die ersten Betas von VB.NET das Verhalten dieser Operatoren tatsächlich geändert haben - es gab Aufruhr, also wurden sie zurück geändert und AndAlso und OrElse (Kurzschluss) wurden eingeführt. Ich kann mir nur vorstellen, welche alternativen Namen sie in Betracht gezogen haben müssen, wenn dies die besten waren ...
AakashM
1
Durch die Angabe von Or und OrElse (| und || in C #) kann der Entwickler auswählen, wie er mit seinem eigenen Code umgehen soll. Mit dem obigen Code müsste ich einen Try-Catch verwenden, um einen Nullwert in der Variablen a zu verarbeiten. Mit OrElse kann der Entwickler dies im else der if-Anweisung als bekanntes mögliches Ergebnis und nicht als Ausnahme behandeln. Dies ist offensichtlicher, wenn die Variable a ein Parameter in einer Methode war, bei der Sie weniger Kontrolle darüber haben, wann der Variablen ein Wert zugewiesen wird (dh außerhalb der Methode)
Kevin Hogg
Kurzschluss ist auch nicht das Standardverhalten von OR und AND in c #. c # hat zwei verschiedene Operatoren für bitweise und logische / Kurzschlussoperationen. && und || Führen Sie logische Vergleiche durch und geben Sie einen booleschen Wert zurück Operatoren sind bitweise und geben einen ganzzahligen Wert zurück. Also wo 1 || 2 gibt "true" zurück, 1 | 2 gibt "3" zurück.
TomXP411
4

OrElse wertet den ersten Ausdruck aus. Wenn er wahr ist, wird mit der Anweisung fortgefahren, während OR zwei Ausdrücke auswertet, bevor mit der Anweisung fortgefahren wird.

Beispiel:

Textbox1.Text= 4

Textbox2.Text= ""

Verwenden von OrElse

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

Ergebnis ist: WAHR


Verwenden von OR

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

            MsgBox("True")
  End If

Ergebnis ist: Fehler kann String nicht in Double konvertieren.

Larz
quelle
3

Die Antwort von Bert ist nicht sehr genau. Das '|' oder '&' ist ein logischer Operator, in C # wird er immer als Bitoperator behandelt. Den folgenden Code finden Sie als Beispiel

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

Das Folgende ist 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

wenn Sie || verwenden Um "a == null" und "a.ToString () ==" sdffd "zu testen, wird die IL sein

 .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

Jetzt können Sie den Unterschied sehen, denken Sie bitte nicht an das '|' oder 'und' als bedingter Operator, es ist nur ein logischer Operator, ich glaube nicht, dass es notwendig ist, ihn zur Beurteilung der Bedingung zu verwenden

FrankX
quelle
2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. Ich habe auch daran geglaubt, bis ich diese Referenz sah, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
user3207158
Ihre Antwort ist aus dem Zusammenhang geraten. Die Frage bezieht sich nicht auf C #, sondern auf VB, wo vier logische Operatoren: AndAlso, Or, OrElse, Not und Xor sowohl logische als auch bitweise Operatoren sind.
Jean-François
0

Sofern Ihre Codelogik nicht das von OrElse bereitgestellte Kurzschlussverhalten erfordert, würde ich den Operator Or verwenden, weil:

  • Die Verwendung von "Oder" ist einfach und erfordert weniger Eingabe.
  • Die Rechenzeitersparnis bei der Verwendung von OrElse ist in den meisten Fällen vernachlässigbar.
  • Am wichtigsten ist, dass die Verwendung von OrElse Fehler in späteren Klauseln verbergen kann, die möglicherweise erst angezeigt werden, wenn diese Bedingungen schließlich von der Programmlogik erfüllt werden.
KnowKnot
quelle
0

Der Grund, warum die Kompilierung im Beispiel fehlschlägt, ist die Reihenfolge der Operationen.

Der Ausdrucksparser versucht zuerst, "dbnull.value or temp" auszuwerten.

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

Der Fehler ist hier, weil Sie kein bitweises ODER zwischen einer Ganzzahl (temp) und dbnull.value ausführen können.

OrElse behebt dies nicht, weil es kurzgeschlossen ist, sondern weil es in der Reihenfolge der Operationen niedriger ist. Daher werden zuerst "temp is dbnull.value" und "3 = 0" ausgewertet, anstatt dass der Parser versucht, dbNull und zu vergleichen temp.

Die Auswertung mit OrElse funktioniert also wie erwartet: (Temp = 3 annehmen)

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

Dies war tatsächlich eine Aufnahmeprüfung bei einem Softwareunternehmen, für das ich früher gearbeitet habe, und es war ein häufiges Problem, auf das ich in VB6 gestoßen bin. Es ist daher eine gute Idee, Ihre Unterausdrücke in Klammern zu setzen, wenn Sie boolesche Operatoren verwenden:

Dies hätte richtig kompiliert:

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

Obwohl, wie alle bereits betont haben, OrElse und AndAlso in diesem Zusammenhang wirklich die richtigen Operatoren sind.

TomXP411
quelle