Se trata esta de una observación que, aunque obvia, en muchos casos puede pasar inadvertida y me parece por tanto interesante destacarla aquí.
Las expresiones condicionales en C# se cortocircuitan. Esto quiere decir que se detienen las comprobaciones en cuanto no es necesario comprobar el resto de condiciones por haber hecho suficientes pruebas para determinar el resultado.
Me explico. Todo el mundo sabe que para que una condición AND proporcione un valor positivo (true) ambas condiciones que se comprueban deben ser positivas (true). Por ello, cuando C# encuentra una condición AND, y verifica que la primera de las dos condiciones que se comparan es falsa, automáticamente deja de comprobar la que falta, puesto que aunque fuese cierta el resultado será falso al serlo ya la primera y, entonces, ¿para qué seguir perdiendo el tiempo?.
Lo mismo ocurre con los otros tipos de operadores booleanos. Por ejemplo, en una expresión OR, si la primera condición es cierta ya no se sigue comprobando el resto puesto que el resultado ya se sabe con la primera (verdadero OR lo-que-sea = verdadero).
Todo esto, aparte de las obvias implicaciones de rendimiento que proporciona, sirve también para salvar ciertas situaciones con expresiones elegantes. Por ejemplo... Imaginemos que el resultado de llamar a una función es una cadena (string). Si el proceso que genera dicha cadena fracasa o (por cualquier otro motivo) no puede ofrecer un resultado razonable, el método devuelve un nulo en lugar de una cadena. Nosotros queremos comprobar que el resultado de llamar al método no devuelva un nulo ni tampoco una cadena vacía, así que escribimos:
string s = MiMetodo();
if (s.Trim() == "" || s == null)
{
....//Lo que sea
}
Esta expresión es errónea y fallará cuando el método devuelva un nulo, aunque parecerá correcta en el resto de los casos (a priori los más comunes). ¿Por qué? Pues porque si 's' es un valor nulo, en cuanto se intente llamar a su método Trim() en la primera condición, se producirá un error puesto que no existe tal método para el objeto nulo.
La forma correcta de escribir esta comprobación es justo al revés:
string s = MiMetodo();
if (s == null || s.Trim() == "")
{
....//Lo que sea
}
De este modo si 's' es nulo la primera condición es cierta y por lo tanto no es necesario comprobar la segunda (hay un OR), y nunca se produce el error por intentar llamar a Trim(). Si por el contrario la cadena es válida la primera condición es falsa y se debe comprobar la segunda, que es lo que necesitamos. La comprobación funciones perfectamente en todos los casos gracias al cortocircuito de expresiones lógicas.
En lenguajes como Visual Basic clásico esta situación no se daba y había que hacer dos condicionales puesto que siempre se comprobaban todas las expresiones, sin cortocircuito. En Visual Basic .NET existe expresiones específicas que cortocircuitan los condicionales (AndAlso, OrElse), ya que los operadores comunes (And, Or, etc...) mantienen el comportamiento antiguo por compatibilidad.
Vale la pena tener en mente estas cuestiones en principio básicas pero muchas veces olvidadas.