2008-12-11 21 views
15

Una respuesta y posterior debate in the comments en otro hilo me hizo preguntar:¿Cuál es la mejor práctica con respecto a la evaluación de cortocircuito C#?

En C# || y & & son las versiones en cortocircuito de los operadores lógicos | y & respectivamente.

Ejemplo de uso:

if (String.IsNullOrEmpty(text1) | String.IsNullOrEmpty(text2) | String.IsNullOrEmpty(text3)) 
{ 
    //... 
} 

frente:

if (String.IsNullOrEmpty(text1) || String.IsNullOrEmpty(text2) || String.IsNullOrEmpty(text3)) 
{ 
    //... 
} 

En términos de práctica, que es el mejor utilizar y por qué codificación?

Nota: Me doy cuenta de que esta pregunta es similar a this question, pero creo que garantiza un debate específico del idioma.

Respuesta

44

En cuanto a la práctica, que es el mejor utilizar la codificación y por qué?

Respuesta simple: utilice siempre las versiones en cortocircuito. Simplemente no hay razón para no hacerlo. Además, hace que su código sea más claro porque expresa su intento : evaluación lógica. Utilizar las operaciones bit a bit (lógicas) implica que solo desea eso: operaciones de bits, no evaluación lógica (aunque MSDN las llama también "operadores lógicos" cuando se aplica a valores booleanos).

Además, dado que un cortocircuito en sólo evalúa lo que se necesita evaluar, a menudo es más rápido, y permite escribir dicho código como

bool nullorempty = str == null || str.Length == 0; 

(Tenga en cuenta que para resolver este problema en particular una mejor función ya existe, es decir, string.IsNullOrEmpty que también usó en su pregunta.) Este código no sería posible con las operaciones lógicas bit a bit porque incluso si str fuera null, se evaluaría la segunda expresión, lo que daría como resultado NullReferenceException.

EDITAR: Si desea efectos secundarios que se producen en un contexto lógico favor todavía no utilizan operaciones bit a bit. Este es un ejemplo típico de ser demasiado inteligente. El próximo mantenedor del código (o incluso usted mismo, después de algunas semanas) verá que este código pensará "hmm, este código se puede borrar para usar operadores condicionales", rompiendo inadvertidamente el código. Lamento a quien sea que esté a cargo de arreglar este error.

En cambio, si usted tiene que confiar en el lateral, efectos, hacerlas explícitas:

bool hasBuzzed = checkMakeBuzz(); 
bool isFrobbed = checkMakeFrob(); 
bool result = hasBuzzed || isFrobbed; 

sentado, tres líneas en lugar de uno. Pero un código mucho más claro como resultado.

+1

esto es una buena respuesta, pero ¿se puede cambiar los operadores "bit a bit" a "lógico" y "lógico" a "condicional"? Esta es la terminología que usa MSDN. técnicamente ambos son "lógicos" pero las versiones duplicadas también tienen cortocircuitos – Jimmy

+0

"El operador Y condicional (&&) realiza un AND lógico de sus operandos bool, pero solo evalúa su segundo operando si es necesario". "http://msdn.microsoft.com/en-us/library/2a723cdk(VS.71).aspx" – Jimmy

+4

Respuesta perfecta. +1 para discusión de efectos secundarios - acordado, para mantenimiento, siempre explícito. 3 LOCs contra pesadilla de mantenimiento, 3 LOC gana sin problemas. –

1

Utilice && y || cuando solo le importa el resultado y desea saber ese resultado lo antes posible y ninguna de sus expresiones tiene efectos secundarios que deben ocurrir incluso si no se cumple la condición booleana. Es decir, casi siempre.

Utilice & y | cuando se debe evaluar cada expresión (por ejemplo, si tiene efectos secundarios de sus expresiones). Pero dado que nunca debe tener efectos secundarios de los que su programa depende que deben ocurrir incluso si no se cumple la condición booleana, probablemente no deba usar & y |.

Por ejemplo, esto probablemente sería excepcionalmente tonto:

if (false & somethingThatUpdatesTheDatabase()) { /* ... */ } 
7

Voy a responder a esta pregunta a la inversa: cuando es el momento única utilizo los operadores lógicos?

A veces usaré las comparaciones lógicas cuando tengo una serie de condicionales (de bajo costo) que deben cumplirse todos. Por ejemplo:

bool isPasswordValid = true; 

isPasswordValid &= isEightCharacters(password); 
isPasswordValid &= containsNumeric(password); 
isPasswordValid &= containsBothUppercaseAndLowercase(password); 

return isPasswordValid; 

En mi opinión, lo anterior es más fácil de leer que:

return (isEightCharacters(password) && 
     containsNumberic(password) && 
     containsBothUppercaseAndLowercase(password)); 

La desventaja es que es un poco más esotérica.

+0

Ah, uso interesante de los operadores de asignación bit a bit. ¡Gracias! – mdwhatcott

+1

Estrictamente en su ejemplo, si la contraseña tiene 7 caracteres, no es válida. Entonces, si contiene Numérico y/o Alto/Minúsculo es irrelevante y no cambia nada. El cortocircuito debería de hecho aplicarse.Si la legibilidad de una declaración de devolución única es un problema, puede cambiar el código a tres líneas que digan: 'if (! RequirementCheck (input)) return false;' entonces la última línea debería decir 'return true;'. Sin embargo, si quisiera cada req. marcado para devolver un mensaje específico, luego combine los mensajes, entonces este ejemplo ya no se aplica a esta pregunta y tenemos más irrelevancia. – Suamere

+0

A veces uso operadores de asignación de bits de esta manera dentro de un bucle, por ej. 'suma int = 0;' ' bool anyOdd = false;' ' foreach (número int en GetNumbers())' '{ ' ' suma + = número;' ' anyOdd | = número% 2 == 1; ' '} ' Pero en esta respuesta estoy de acuerdo con @Suamere en que el cortocircuito es más limpio. – hypehuman

Cuestiones relacionadas