2008-08-07 20 views
14

En C#, (¿y en qué orden el runtime evalúa una instrucción lógica?C# orden lógico y comportamiento del compilador

Ejemplo:

DataTable myDt = new DataTable(); 
if (myDt != null && myDt.Rows.Count > 0) 
{ 
    //do some stuff with myDt 
} 

¿Qué afirmación no el tiempo de ejecución evaluar primero -

myDt != null 

o:

myDt.Rows.Count > 0 

?

¿Hay algún momento en que el compilador alguna vez evalúe la afirmación al revés? ¿Quizás cuando un operador "O" está involucrado?


& se conoce como un operador de bits lógico y siempre habrá evaluar todas las sub-expresiones

¿Qué es un buen ejemplo de cuándo utilizar el operador de bits en lugar del "corto circuited boolean "?

Respuesta

16

C#: De izquierda a derecha, y el procesamiento se detiene si un no-partido (como resultado false) se encuentra.

+0

Como han indicado otros, el cortocircuito en el operador && ocurre en ** falso **. – Broam

2

El de la izquierda, luego se detiene si es nulo.

Editar: En vb.net se evaluará tanto y posiblemente generará un error, a menos que utilice AndAlso

0

He oído en alguna parte que los compiladores funcionan al revés, pero no estoy seguro de cuán cierto es esto.

6

vb.net

if(x isNot Nothing AndAlso x.go()) then 
  1. evaluación se realiza de izquierda a derecha
  2. AndAlso operador se asegura de que sólo si el lado izquierdo era cierto, se evaluará el lado derecho (muy importante, ya que ifx no es nada x.go se bloqueará)

Puede usar y en lugar deAndAlso en vb. en cuyo caso, el lado izquierdo también se evalúa primero, pero el lado derecho se evaluará independientemente del resultado.

Mejor práctica: Siempre use AndAlso, a menos que tenga una muy buena razón para no hacerlo.


Se preguntó en un seguimiento de por qué o cuando alguien usaría Y en vez de AndAlso (o & en lugar de & &): Aquí se muestra un ejemplo:

if (x.init() And y.init()) then 
    x.process(y) 
end 
y.doDance() 

En este caso , Quiero iniciar tanto X como Y. Y debe inicializarse en orden para y.DoDance para poder ejecutar. Sin embargo, en la función init() también estoy haciendo algo extra, como verificar que el socket esté abierto, y solo si funciona bien, para ambos, debo seguir adelante y hacer el x.process (y).

Nuevamente, esto probablemente no sea necesario y no elegante en el 99% de los casos, es por eso que dije que el valor predeterminado debería ser usar y también.

2

El concepto de modestia se refiere a la sobrecarga del operador. en la declaración:

if(A && B){ 
    // do something 
} 

A se evalúa primero, si se evalúa como falso, B nunca se evalúa. Lo mismo se aplica a

if(A || B){ 
    //do something 
} 

A se evalúa en primer lugar, si se evalúa como verdadera, B nunca se evalúa.

Este concepto, sobrecarga, se aplica a (creo) todos los lenguajes de estilo C, y muchos otros también.

4

ZombieSheep está inactivo. El único "error" que podría estar esperando es que esto solo es cierto si está usando el operador & &. Al utilizar el operador &, ambas expresiones se evaluarán todas las veces, independientemente de si una o ambas evalúan a falso.

if (amHungry & whiteCastleIsNearby) 
{ 
    // The code will check if White Castle is nearby 
    // even when I am not hungry 
} 

if (amHungry && whiteCastleIsNearby) 
{ 
    // The code will only check if White Castle is nearby 
    // when I am hungry 
} 
4

Tenga en cuenta que hay una diferencia entre & & & y en relación con la cantidad de su expresión se evalúa.

& & se conoce como un booleano Y en cortocircuito, y, como señalaron otros aquí, se detendrá temprano si se puede determinar el resultado antes de que se evalúen todas las sub expresiones.

& es conocido como un operador bit a bit lógico y siempre evaluará todas las subexpresiones.

Como tal:

if (a() && b()) 

solamente llamaremos b si unos rendimientos verdadera.

embargo

, esto:

if (a() & b()) 

Will siempre llame tanto un y b, a pesar de que el resultado de llamar un es falso y por lo tanto sabe que falsa independientemente del resultado de llamar al b.

Esta misma diferencia existe para || y | operadores.

4

Algunos idiomas tienen situaciones interesantes donde las expresiones se ejecutan en un orden diferente. Estoy pensando específicamente en Ruby, pero estoy seguro de que lo tomaron prestado de otra parte (probablemente Perl).

Las expresiones en la lógica permanecerán izquierda a derecha, pero por ejemplo:

puts message unless message.nil? 

Lo anterior evaluarán "message.nil?" primero, luego si se evalúa como falso (a menos que sea como si, excepto que se ejecuta cuando la condición es falsa en lugar de verdadera), se ejecutará "poner mensaje", que imprime el contenido de la variable de mensaje en la pantalla.

Es una forma interesante de estructurar tu código a veces ... Personalmente me gusta utilizarlo para líneas muy cortas 1 como la anterior.

Editar:

para que sea un poco más claro, lo anterior es lo mismo que:

unless message.nil? 
    puts message 
end 
1

Nopes, al menos, el compilador de C# no funciona hacia atrás (en cualquiera & & o | |). Está de izquierda a derecha.

1

¿Cuál es un buen ejemplo de cuándo utilizar el operador bit a bit en lugar del "booleano cortocircuitado"?

Supongamos que tiene indicadores, por ejemplo, para los atributos del archivo. Suponga que ha definido leído como 4, escribo como 2, y EXEC como 1. En binario, eso es:

READ 0100 
WRITE 0010 
EXEC 0001 

Cada bandera tiene un conjunto de bits, y cada uno es único. Los operadores de bits permiten combinar estas banderas:

flags = READ & EXEC; // value of flags is 0101 
5

@shsteimer

El concepto se refiere a la modestia es la sobrecarga de operadores. en la declaración: ... A se evalúa primero, si se evalúa como falso, B nunca se evalúa. Lo mismo se aplica a

Eso no es una sobrecarga del operador. Sobrecarga del operador es el término dado para permitirle definir un comportamiento personalizado para los operadores, como *, +, =, etc.

Esto permitirá escribir su propia clase 'Entrar', y luego hacer

a = new Log(); // Log class overloads the + operator 
a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects. 

Hacer esto

a() || b() // be never runs if a is true 

se llama en realidad Short Circuit Evaluation

0

Se utiliza & cuando se desea específicamente para evaluar todas las subexpresiones, muy probablemente porque tienen los efectos secundarios que desea, aunque el resultado final será falso y por lo tanto no ejecutar entonces parte de su si -estancia.

Tenga en cuenta que & y | opera tanto para las máscaras bit a bit como para los valores booleanos y no es solo para operaciones a nivel de bit.Son llamados en modo bit, pero se definen para los enteros y los tipos de datos booleanos en C#.

1

Cuando todo está en línea, se ejecutan de izquierda a derecha.

Cuando las cosas están anidadas, se ejecutan de manera interna a externa. Esto puede parecer confuso, ya que por lo general lo que es "más interno" está en el lado derecho de la línea, por lo que parece como que va al revés ...

Por ejemplo

a = Foo(5, GetSummary("Orion", GetAddress("Orion"))); 

Las cosas suceden así:

  • llamada GetAddress con el literal "Orion"
  • llamada GetSummary con el literal "Orion" y el resultado de GetAddress
  • llamada Foo con el literal 5 y el resultado de GetSummary
  • asignar este valor a a
8

realizo esta pregunta ya ha sido contestada, pero me gustaría lanzar en otra parte de la información que está relacionado con el tema.

En idiomas, como C++, donde realmente se puede sobrecargar el comportamiento del & & y || operadores, es muy recomendable que no haga esto. Esto se debe a que cuando sobrecarga este comportamiento, termina forzando la evaluación de ambos lados de la operación. Esto hace dos cosas:

  1. Rompe el mecanismo de evaluación diferida porque la sobrecarga es una función que debe invocarse, y por lo tanto ambos parámetros se evalúan antes de llamar a la función.
  2. El orden de evaluación de dichos parámetros no está garantizado y puede ser específico del compilador. Por lo tanto, los objetos no se comportarían de la misma manera que en los ejemplos enumerados en la pregunta/respuestas anteriores.

Para obtener más información, lea el libro de Scott Meyers, More Effective C++. ¡Aclamaciones!

1

Me gustan las respuestas de Orion.Voy a añadir dos cosas:

  1. El periódico de izquierda a derecha todavía se aplica primero
  2. El interior-exterior-para asegurar que todos los argumentos que se resuelvan antes de llamar a la función

decir que tener el siguiente ejemplo:

a = Foo(5, GetSummary("Orion", GetAddress("Orion")), 
      GetSummary("Chris", GetAddress("Chris"))); 

Aquí está la orden de ejecución:

  1. GetAddress("Orion")
  2. GetSummary("Orion", ...)
  3. GetAddress("Chris")
  4. GetSummary("Chris", ...)
  5. Foo(...)
  6. Asigna a a

No puedo hablar acerca de los requisitos legales de C# 's (aunque lo hice probar un ejemplo similar utilizando Mono antes de escribir esta publicación), pero esta orden está garantizada en Java.

Y para completar (dado que este es un hilo de lenguaje también), existen lenguajes como C y C++, donde el orden no está garantizado a menos que exista un punto de secuencia. Referencias: 1, 2. Al responder la pregunta del hilo, sin embargo, && y || son puntos de secuencia en C++ (a menos que estén sobrecargados, también vea la excelente respuesta de OJ). Por lo que algunos ejemplos:

  • foo() && bar()
  • foo() & bar()

En el caso &&, foo() se garantiza la ejecución antes bar() (si este último está dirigido a todos), ya que && es un punto de secuencia. En el caso &, no se hace tal garantía (en C y C++), y de hecho bar() puede ejecutarse antes de foo(), o viceversa.

9

"C#: De izquierda a derecha, y el procesamiento se detiene si se encuentra una coincidencia (se evalúa como verdadera)".

Zombie sheep está mal, no es suficiente para votar.

La pregunta es sobre el operador & &, no el || operador.

En el caso de & & la evaluación se detendrá si se encuentra un FALSO.

En el caso de || la evaluación se detiene si se encuentra un VERDADERO.

+0

Sí. Tienes toda la razón. Sin embargo, espero que mi respuesta original haya sido interpretada de la manera correcta. Ciertamente, no era mi intención engañar a nadie. – ZombieSheep

0

@csmba:

Se preguntó en un seguimiento por qué o cuándo habría que nadie utilice Y en vez de AndAlso (o & en lugar de & &): Aquí se muestra un ejemplo:

if (x.init() And y.init()) then 
    x.process(y) 
end 
y.doDance() 

En en este caso, quiero iniciar tanto X como Y. Y debe inicializarse para que y.DoDance pueda ejecutarse. Sin embargo, en la función init() también estoy haciendo algo extra, como comprobar que un socket esté abierto, y solo si funciona bien, para ambos, debo seguir adelante y hacer el x.process (y).

Creo que esto es bastante confuso. Aunque su ejemplo funciona, no es el caso típico para usar And (y probablemente escribiría esto de manera diferente para hacerlo más claro). And (& en la mayoría de los demás idiomas) es en realidad la operación bit a bit. Se podría utilizar para el cálculo de operaciones de bits, por ejemplo, la eliminación de un bit de bandera o banderas de enmascaramiento y pruebas: lenguaje de programación

Dim x As Formatting = Formatting.Bold Or Formatting.Italic 
If (x And Formatting.Italic) = Formatting.Italic Then 
    MsgBox("The text will be set in italic.") 
End If 
Cuestiones relacionadas