Ou contre OrElse

95

Quelle est la différence entre or et OrElse ?

if temp is dbnull.value or temp = 0

produit l'erreur:

L'opérateur '=' n'est pas défini pour le type 'DBNull' et le type 'Integer'.

alors que celui-ci fonctionne comme un charme !?

if temp is dbnull.value OrElse temp = 0
Ou sinon
la source

Réponses:

145

OrElseest un opérateur de court-circuit , Orne l'est pas.

Par la définition de l'opérateur booléen 'ou', si le premier terme est Vrai, alors le tout est définitivement vrai - nous n'avons donc pas besoin d'évaluer le deuxième terme.

OrElsele sait, donc n'essaye pas d'évaluer temp = 0une fois qu'il est établi quetemp Is DBNull.Value

Orne le sait pas et tentera toujours d'évaluer les deux termes. Quand temp Is DBNull.Value, il ne peut pas être comparé à zéro, alors il tombe.

Vous devriez utiliser ... eh bien, celui qui a du sens.

AakashM
la source
2
Donc Ou n'a de sens que lorsque j'appelle une fonction après ou qui a des effets secondaires dont dépend mon code?
Ralph M. Rickenbach
4
Ou a du sens dans tous les cas où le deuxième élément ne déclenche pas d'erreur si le premier est vrai ...
awe
4
@ malach: Je suppose que oui (vous obtenez vraiment le comportement OrElse par défaut dans la plupart des autres langages): Ce n'est pas une bonne idée d'appeler des fonctions avec des effets secondaires dans des conditions composées, cela rend le code illisible.
Utaal
4
@ awe: oui, mais pourquoi voulez-vous même perdre du temps à évaluer quelque chose qui, par définition, ne changera pas le résultat de l'expression?
Utaal
3
@MarkJ: Je ne pense pas vraiment que quatre caractères supplémentaires perturbent la lisibilité. D'un autre côté, utiliser un opérateur qui dépend de l'existence d'effets secondaires (comme l'a écrit Malach) pour avoir un sens sonne comme une mauvaise idée (et peut rendre la lisibilité plus difficile!). Je considérerais les effets secondaires dans de tels endroits comme un grand non-non, et je ne peux penser à aucune situation dans laquelle je préférerais "Ou" à "OrElse". Il est dommage que ces opérateurs fonctionnent de cette façon, car le comportement "OrElse" est probablement ce à quoi la plupart s'attendent même en utilisant "Or" (surtout en venant d'autres langages).
Kjartan
42

C'est le même comportement qu'avec C #, où tout le monde utilise le Coditional Or (||) et le Conditional And (&&), où vous avez également le Or normal (|) et le And normal (&). Donc, comparer C # à VB.Net est:

| => Ou

|| => OuElse

& => Et

&& => EtAussi

Les opérateurs booléens conditionnels sont très utiles pour empêcher les constructions if imbriquées. Mais parfois, les opérateurs booléens normaux sont nécessaires pour s'assurer d'atteindre les deux chemins de code.

Bert Heesbeen
la source
9
Je n'ai jamais vraiment su que c'était disponible. Merci pour les nouvelles informations. Bon à savoir, même si je ne vois pas vraiment de situation dans laquelle je voudrais utiliser "|". Je pense qu'il faudrait la deuxième condition pour que les effets secondaires aient un sens, et cela en soi n'a pas de sens à mon avis! ;)
Kjartan
7
Eh, pour autant que je sache, |et ce &sont des opérateurs binaires en C #, pas du tout des opérations booléennes.
Nyerguds
8

OrElse est court-circuité , cela signifie qu'un seul côté de l'expression sera testé si le premier côté correspond.

Tout comme AndAlso ne testera qu'un côté de l'expression si la première moitié est un échec.

Stevehipwell
la source
4

(J'ai regardé d'autres réponses et réalisé que j'avais terriblement tort)

L'opérateur OrElse "effectue une disjonction logique de court-circuit sur deux expressions", c'est-à-dire: si l'opérande gauche est vrai et que l'expression entière est donc garantie vraie, l'opérande droit ne sera même pas évalué (cela est utile dans des cas comme:

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

pour éviter une NullReferenceException lancée par l'opérande de droite.

Je suis sincèrement étonné que cette ( évaluation paresseuse ) ne soit pas le comportement par défaut de oret andcomme c'est le cas en C / C ++ et C # (et dans de nombreux autres langages ...)

Utaal
la source
7
Le truc, c'est que dans VB classic, il y avait juste Et et Ou, qui n'étaient pas en court-circuit. Je pense que j'ai raison de dire que les premières bêtas de VB.NET ont en fait changé le comportement de ces opérateurs - il y a eu un tollé, donc ils ont été modifiés et AndAlso et OrElse (court-circuit) ont été introduits. Je ne peux qu'imaginer les noms alternatifs qu'ils ont dû considérer si c'étaient ceux qui étaient les meilleurs ...
AakashM
1
En fournissant Or et OrElse (| et || en C #), cela permet au développeur de choisir comment il gère son propre code. En utilisant le code ci-dessus, je devrais utiliser un crochet d'essai autour de lui pour gérer une valeur nulle dans la variable a. OrElse permet au développeur de gérer cela dans le else de l'instruction if comme un résultat possible connu plutôt qu'une exception. Cela est plus évident si la variable a était un paramètre dans une méthode, où vous avez moins de contrôle sur le moment où une valeur est attribuée à la variable (c'est-à-dire en dehors de la méthode)
Kevin Hogg
Le court-circuit n'est pas non plus le comportement par défaut de OR et AND dans c #. c # a deux opérateurs différents pour les opérations binaires et logiques / de court-circuit. && et || effectuer des comparaisons logiques et renvoyer une valeur booléenne Les & et | les opérateurs sont au niveau du bit et renvoient une valeur entière. Alors où 1 || 2 renvoie "vrai", 1 | 2 renvoie "3".
TomXP411
4

OuElse évalue la première expression, puis si c'est vrai, il passera à l'instruction tandis que OU évalue deux expressions avant de passer à leur instruction.

Exemple:

Textbox1.Text= 4

Textbox2.Text= ""

Utiliser OrElse

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

Le résultat est: TRUE


Utiliser OR

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

            MsgBox("True")
  End If

Le résultat est: L' erreur ne peut pas convertir la chaîne en double.

Larz
la source
3

La réponse de Bert n'est pas très précise. Le '|' ou '&' est un opérateur logique, en C #, il est toujours traité comme un opérateur de bit, veuillez consulter le code suivant comme exemple

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

Ce qui suit est 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

lorsque vous utilisez || pour tester "a == null" et "a.ToString () ==" sdffd ", l'IL sera

 .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

Maintenant, vous pouvez voir la différence, ne pensez pas que le «|» ou 'et' comme opérateur conditionnel, c'est juste un opérateur logique, je ne pense pas qu'il soit nécessaire de l'utiliser pour juger la condition

FrankX
la source
2
The '|' or '&' is logical operator, in C #, it always treat as bit operator. J'y croyais aussi, jusqu'à ce que j'aie vu cette référence, msdn.microsoft.com/en-us/library/kxszd0kx.aspx
user3207158
Votre réponse est hors contexte. La question ne concerne pas C # mais plutôt VB où quatre opérateurs logiques: And, AndAlso, Or, OrElse, Not et Xor sont à la fois des opérateurs logiques et Bitwise.
Jean-François
0

À moins que votre logique de code ne nécessite le comportement de court-circuit fourni par OrElse, je pencherais vers l'utilisation de l'opérateur Or car:

  • L'utilisation de "Ou" est simple et nécessite moins de frappe.
  • Le gain de temps de calcul lié à l'utilisation d'OrElse est négligeable dans la plupart des cas.
  • Plus important encore, l'utilisation d'OrElse peut masquer des erreurs dans des clauses ultérieures qui peuvent ne pas être initialement révélées jusqu'à ce que ces conditions soient finalement remplies par la logique du programme.
KnowKnot
la source
0

La raison pour laquelle la compilation échoue dans l'exemple est l'ordre des opérations.

L'analyseur d'expression essaie d'abord d'évaluer "dbnull.value ou temp".

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

L'erreur est là, car vous ne pouvez pas faire un OU au niveau du bit entre un entier (temp) et dbnull.value.

OrElse corrige ce problème, non pas parce qu'il est court-circuité, mais parce qu'il est plus bas dans l'ordre des opérations , et donc "temp is dbnull.value" et "3 = 0" sont évalués en premier, plutôt que l'analyseur essayant de comparer dbNull et temp.

Ainsi, l'évaluation avec OrElse fonctionne comme prévu: (supposons que 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

C'était en fait lors d'un examen d'entrée dans une société de logiciels pour laquelle je travaillais, et c'était un problème courant que j'avais l'habitude de rencontrer dans VB6. C'est donc une bonne idée de mettre entre parenthèses vos sous-expressions lorsque vous utilisez des opérateurs booléens:

Cela aurait compilé correctement:

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

Bien que, comme tout le monde l'a déjà souligné, OrElse et AndAlso sont vraiment les bons opérateurs à utiliser dans ce contexte.

TomXP411
la source