2010-05-27 6 views
13

acabo de venir a través de este fragmento de código en algún intercambio de código 2010 y me preguntaba si alguien sabía por qué el programador ha hecho de esta manera. Nunca he visto una instrucción If formateada de esta manera. Parece tan al revés que debe haber una buena razón para ello ??C# if declaración. funcionamiento interno Q

if (true == MsgItem.HasAttachments) 
{ 
    // Code 
} 

Supongo que podría tener alguna optimización sobre las otras formas de codificación de la misma cosa;

if (MsgItem.HasAttachments) 
{ 
    // Code 
} 

o

if (MsgItem.HasAttachments == true) 
{ 
    // Code 
} 

No es una gran cosa ¡Soy apenas curioso.

Gracias, Mike

ACTUALIZACIÓN: Gracias por todos los puntos interesantes planteadas. Parece que el resumen se debe a los estándares de codificación heredados.

+1

¿Hábito del programador? –

+0

posible duplicado de [== Operador y operandos] (http://stackoverflow.com/questions/677264/operator-and-operands) – ChrisF

+4

"debe haber una buena razón para ello" == falso –

Respuesta

31

Es un hábito resabio de C o C++ en la que podría querer hacer:

if (i = 1) { 
} 

Esto asigna accidentalmente 1-i en lugar de hacer una comparación.

Invertir el orden en el cheque evita este error común.

if (1 = i) { 
} 

Eso no se compilará, y es fácil ver que, por error, en lugar de tecleado ===.

Este es todavía relevante para bools en C# porque el valor de una asignación es el valor que se le asignó.

para ellos:

if (SomeBoolVar = true) { 
} 

siempre será cierto, porque está almacenando en trueSomeBoolVar que evalúa a true. Un pequeño error que puede ser difícil de rastrear.

+14

Las personas que usan 'if (SomeBoolVar = true)' en lugar de 'if (SomeBoolVar)' deben cortarse las manos :-) – paxdiablo

+1

Haha, o al menos sus pulgares, por lo que la barra espaciadora es un dolor en el trasero para utilizar. (@paxdia) – jjnguy

+3

El compilador de C# de Microsoft también arrojará una advertencia si accidentalmente usa '=' en lugar de '==' en una expresión condicional. – LukeH

11

Estos se llaman "Yoda Conditions" - la idea original es que si accidentalmente introduce un único =, la compilación fallará debido a que el valor de la constante es en el lado izquierdo.

14

C++ y C programadores a veces ponen constantes en primer lugar, para evitar accidentalmente escribir

if (variable = constant) 

que realizar una asignación.

En particular, explícitamente para las comparaciones booleanas, asumiendo HasAttachments se puede escribir, esta declaración sería compilar y ejecutar sin advertencias , pero no tiene el comportamiento previsto en C#:

if (MsgItem.HasAttachments = true) 

Para las expresiones no booleanas, esto no suele ser un problema en C# porque la condición de una declaración if debe ser implícitamente convertible a bool ... y para las expresiones booleanas, se prefiere de todos modos la forma central:

if (MsgItem.HasAttachments) 

estaría sorprendido si no tuviera ningún impacto rendimiento en todo - y probablemente ningún impacto en el IL generado para empezar.


Vaya - MS compilador de C# en efecto, advierten de esto:

advertencia CS0665: Asignación en la expresión condicional es siempre constante; ¿Querías usar == en lugar de =?

No lo he probado en Mono though; eso puede o no dar una advertencia. Ciertamente es válido código de C#.

+0

Lo creas o no, se traduce a * ligeramente * diferente IL. Ver la respuesta de jeffmaphone a [una pregunta muy similar que publiqué hace mucho tiempo] (http://stackoverflow.com/questions/1070063/does-if-bool-true-require-one-ste-than-if-bool) –

+0

@Dan: la respuesta de jeffmaphone es usar C++, no C#. En C# compilarán exactamente la misma IL. – LukeH

+0

@LukeH: Ha, gracias por recordarme (debería haber vuelto a leer la respuesta antes de vincularla; descuidé darme cuenta de que esta pregunta es específica de C# mientras que la mía era independiente del idioma). ¡Y me doy cuenta de que tú eres quien señaló este hecho en la pregunta! –

1

quizás el operador == se ha sobrecargado y MsgItem.HasAttachments tiene más información que simplemente bool? No lo sé. Solo una idea.

+1

Ah, el viejo "Daily WTF" {verdadero, falso, tal vez} escribe :-) – paxdiablo

+1

No, si sobrecargas operadores de igualdad las cosas no son siempre lo que parecen. Si tiene 'verdadero == MsgItem.HasAttachments', ejecutará el operador == para la clase bool y pasará MsgItem.HasAttachments a la implementación del operador. Si lo tiene al revés, ejecutará la implementación del operador == en el tipo de HasAttachments y pasará "verdadero" en él. Claramente, el comportamiento no tiene que ser el mismo. Entonces, al menos cuando se sobrecarga a los operadores, el orden a menudo hace la diferencia. – Cobusve

0

Este es un requisito común al escribir código de misión crítica. Está ahí para evitar asignaciones accidentales cuando quisiste hacer un chequeo. En un lenguaje como C#, el compilador te advertirá al respecto, por lo que no es tan necesario, pero es un hábito sobrante para muchos programadores.

6

Debido a que el programador es un payaso :-) El punto de condiciones booleanas es que las nombre de tal manera que hacen sentido como booleanos:

if (MsgItem.HasAttachments) 

y esto claramente lo hace no lo hago saber por qué el codificador se pegó un tiro en el pie al probar la igualdad contra true.

Porque, con toda seriedad, true == MsgItem.HasAttachments es solo otro booleano, entonces ¿dónde se detiene?

if (true == MsgItem.HasAttachments) 
if (true == (true == MsgItem.HasAttachments)) 
if (true == (true == (true == MsgItem.HasAttachments))) 
: : : 

Y así sucesivamente, ad infinitum.

Todo el truco de usar la primera constante para evitar el problema de forma accidental usando = asignación en lugar de == igualdad no debería ser un problema aquí, ya que no debería estar mirando un valor lógico en contra de cualquiera true o false.Usted debe utilizar uno de:

if (cond) 
if (!cond) 
2

Bajo mono, todos ellos generan el mismo IL (ldloc.0; brfalse <LOC>):

Fuente:

using System; 
class Foo 
{ 
    static void Main() 
    { 
     bool bar = Console.ReadLine() == "bar"; 
     if (bar) 
     { 
      Console.WriteLine("bar"); 
     } 

     if (true == bar) 
     { 
      Console.WriteLine("true == bar"); 
     } 

     if (bar == true) 
     { 
      Console.WriteLine("bar == true"); 
     } 
    } 
} 

IL:

// snip... 
IL_000a: call bool string::op_Equality(string, string) 
IL_000f: stloc.0 
IL_0010: ldloc.0 
IL_0011: brfalse IL_0020 

IL_0016: ldstr "bar" 
IL_001b: call void class [mscorlib]System.Console::WriteLine(string) 
IL_0020: ldloc.0 
IL_0021: brfalse IL_0030 

IL_0026: ldstr "true == bar" 
IL_002b: call void class [mscorlib]System.Console::WriteLine(string) 
IL_0030: ldloc.0 
IL_0031: brfalse IL_0040 
// snip... 

Personalmente, me vuelven loco cuando la gente lo hace if (SomePredicate() == true). A menos que devuelva un objeto con un operador == sobrecargado, la comparación con true es completamente innecesaria. ¿Por qué detenerse en una comparación?

// make extra sure SomePredicate returns true 
if ((SomePredicate() == true) == true) 
{ 
    // ... 
} 
3

Hay un perfectamente bien razón para escribir if (true == myvar): la variable (o expresión) podrían no ser una expresión booleana - que podría ser un bool?. La expresión entonces sería equivalente a if(myvar ?? false), y prefiero esta segunda sintaxis, ya que es obvio que se trata de un valor que se puede añadir a nulos. Es técnicamente posible que se esté utilizando un operador == personalizado (potencialmente en combinación con una conversión de tipo implícita), pero eso es bastante improbable ya que hacer algo así generalmente es desaprobado y tampoco es práctico ni práctico.

Colocar la constante primero, como muchos otros han señalado, puede reducir los errores accidentales, personalmente, no creo que esos errores ocurran con la frecuencia suficiente como para importar, pero no puede dañar.

Sin embargo, lo más probable es que el autor original estuviera un poco confundido desde el momento en que escribió el código.