2009-12-11 15 views
6

¿Los siguientes 2 fragmentos de código logran lo mismo?¿Son estas 2 declaraciones idénticas?

Mi código original:

if (safeFileNames != null) 
{ 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
} 
else 
{ 
    this.SafeFileNames = false; 
} 

Qué pensamiento ReSharper era una idea mejor:

this.SafeFileNames = safeFileNames != null && 
        Convert.ToBoolean(safeFileNames.Value); 

creo que el código anterior es mucho más fácil de leer, ninguna razón de peso para cambiarlo?
¿Se ejecutará más rápido, y lo más importante, el código hará exactamente lo mismo?

Además, si nos fijamos en la sección: Convert.ToBoolean(safeFileNames.Value);, ¿entonces esto podría causar una excepción de referencia nula?

this.SafeFileNames = bool 

safeFileNames local es un objeto personalizado inflexible, aquí es la clase:

public class Configuration 
    { 
     public string Name 
     { 
      get; 
      set; 
     } 
     public string Value 
     { 
      get; 
      set; 
     } 
    } 
+3

Usted no recibirá un 'NullReferenceExcepton' ya que la primera parte de la declaración 'safeFileNames! = null' cortará en cortocircuito y nunca golpearás' Convert.ToBoolean (safeFileNames.Value) '- esa es la y el && funciona. – Nate

+2

No causaría una excepción de referencia nula debido a la evaluación perezosa de C#. La instrucción && siempre se evalúa a la izquierda y luego a la derecha. Pero si el lado izquierdo es falso, no molestará evaluar el lado derecho, ya que el resultado lógico ya está determinado. Entonces, si safeFileNames es nulo, entonces la llamada Convert.ToBoolean nunca se realiza. Este tipo de cosas es bastante común en el código. –

+1

Entonces, si comprendo que && - si la parte izquierda es falsa, devuelve falso ... de lo contrario, evalúa la parte correcta y devuelve el resultado de la parte correcta. –

Respuesta

24

El hecho de que haya hecho la pregunta me sugiere que se prefiere la primera. Es decir, me parece que su pregunta implica que usted cree que el primer código es más fácil de entender, y no está seguro si el segundo es equivalente. Un objetivo principal del diseño de software es administrar la complejidad. Si le resulta confuso ahora, también puede serlo más adelante, o para cualquiera que admita su código más adelante.

+4

Esta es una gran respuesta. – jason

+0

+1 a KISS [15] –

+0

Muy buena manera de verlo. –

5

Ambas declaraciones hacen exactamente lo mismo. Cuál usar es una cuestión de preferencia, pero prefiero la versión de Resharper. Piezas más concisas y menos móviles. Es más fácil ver la intención del código.

+0

¿Qué pasa si this.SafeFileNames es nulo? Sin duda, intentar Convert.ToBoolean en un nulo, ¿causaría una excepción de referencia nula? –

+0

@JL: la segunda cláusula nunca se ejecutaría si SafeFileNames fuera nulo – Randolpho

+0

Cortocircuito para la victoria. –

1

Son lo mismo. El & & es un operador de cortocircuito por lo que la segunda mitad de la expresión no evaluará si safeFileNames es nulo.

1

Son lo mismo. En el juego de una sola línea, si la primera condición falla, la segunda no se evalúa. Entonces no obtienes una referencia nula.

Apuesto a que el IL es el mismo en ambos casos.

Prefiero la segunda versión.

2

Reduce la complejidad ciclomática de su código utilizando la sugerencia de reafilar.

Ya sea que sea más fácil de leer o no, es una opinión personal, sin embargo, prefiero la sugerencia que inspiró.

Son idénticos y, si desea facilitar la lectura, que también podrían sugerir lo siguiente:

if (safeFileNames != null) 
    this.SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
else 
    this.SafeFileNames = false; 

o

this.SafeFileNames = safeFileNames != null ? Convert.ToBoolean(safeFileNames.Value) : false 
+0

Nota: Quitar los frenillos cuando no es necesario hace que el código se vea mejor, una vez más, basado en la opinión. –

+0

@Aequtarium, su respuesta no es incorrecta o ineficiente. Simplemente no es tan emocionante como los demás, supongo. Votándote. –

+0

Es una opinión, pero vale la pena señalar que StyleCop marcará esto como un error. La consistencia es un factor; el otro introduce un error cuando agrega su segunda instrucción en un if (sin otro) y olvida agregar también sus llaves. IDE usualmente lo sangrará y le notificará, pero si está usando el Bloc de notas visual ... –

1

Sí ambas declaraciones va a hacer lo mismo, no lo hace tiene que tomar sugerencias de re-sharpers como un evangelio, lo que un hombre considera que un código legible es otro desastre del hombre.

Existen otras formas de hacer lo que intenta hacer que podrían ser más legibles, ¿qué tipo de valor es safeFileNames? Parece que puede ser un Bool Nullable?Si es así, simplemente escriba,

this.SafeFileNames = safeFileNames.GetValueOrDefault(); 
0

Lógicamente, son idénticos. Cualquier diferencia de rendimiento probablemente sería insignificante. Es posible que la segunda forma se traduzca en un código binario más eficiente en algunas plataformas, ya que la segunda forma elimina un condicional. Los condicionales (ejecución especulativa incorrecta) pueden arruinar la tubería de instrucciones de su CPU en trabajos intensivos de CPU. Sin embargo, tanto el IL como el JITter necesitan emitir un código de calidad adecuada para que esto haga una gran diferencia.

Estoy de acuerdo con su sentido de la legibilidad, pero no creo que todos lo compartan.

5

Aquí está IL para ambos códigos. Tomé su código y creé una aplicación de consola para echar un vistazo a la IL. Como se puede ver en la IL resultante, un método (método2) es 4 bytes más corto, pero el IL que se ejecuta para ambos es prácticamente el mismo, por lo que respecta al rendimiento ... no se preocupe por eso. Ambos tendrán el mismo rendimiento. Concéntrese más en cuál es más fácil de leer y mejor demuestra su intención.

Mi código:

class Program 
{ 
    static void Main(string[] args) 
    { 


    } 
    public void method1() 
    { 
     bool? safeFileNames = null; 

     if (safeFileNames != null) 
     { 
      SafeFileNames = Convert.ToBoolean(safeFileNames.Value); 
     } 
     else 
     { 
      SafeFileNames = false; 
     } 
    } 
    public void method2() 
    { 
     bool? safeFileNames = null; 
     SafeFileNames = safeFileNames != null && Convert.ToBoolean(safeFileNames.Value); 
    } 
    public static bool SafeFileNames { get; set; } 
} 

La IL para el método 1:

.method public hidebysig instance void method1() cil managed 
{ 
    // Code size  42 (0x2a) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_0023 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0022: ret 
    IL_0023: ldc.i4.0 
    IL_0024: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0029: ret 
} // end of method Program::method1 

La IL para metodo2:

.method public hidebysig instance void method2() cil managed 
{ 
    // Code size  38 (0x26) 
    .maxstack 1 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<bool> safeFileNames) 
    IL_0000: ldloca.s safeFileNames 
    IL_0002: initobj valuetype [mscorlib]System.Nullable`1<bool> 
    IL_0008: ldloca.s safeFileNames 
    IL_000a: call  instance bool valuetype [mscorlib]System.Nullable`1<bool>::get_HasValue() 
    IL_000f: brfalse.s IL_001f 
    IL_0011: ldloca.s safeFileNames 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<bool>::get_Value() 
    IL_0018: call  bool [mscorlib]System.Convert::ToBoolean(bool) 
    IL_001d: br.s  IL_0020 
    IL_001f: ldc.i4.0 
    IL_0020: call  void ConsoleApplication5.Program::set_SafeFileNames(bool) 
    IL_0025: ret 
} // end of method Program::method2 
+1

Si pudiera dar más de 1 punto, me encantaría que las personas revisen el IL para determinar las diferencias reales. –

+0

+1 por el esfuerzo extremo, ¡y muchas gracias! –

+0

Parecía una buena excusa para desempolvar ildasm y jugar por un tiempo :-) – jvilalta

Cuestiones relacionadas