2009-04-08 7 views
24

Al asignar un valor predeterminado valor predeterminado para un campo (en este caso falsa a un bool), FxCop dice:¿Por qué FxCop cree que inicializar los campos al valor predeterminado es malo?

Resolution : "'Bar.Bar()' initializes field 'Bar.foo' 
       of type 'bool' to false. Remove this initialization 
       because it will be done automatically by the runtime." 

Ahora, sé que el código como int a = 0 o bool ok = false es la introducción de una cierta redundancia, pero me parece una práctica de código muy, muy buena, en la que mis profesores insistieron con razón, en mi opinión.

No solo la penalización de rendimiento es muy pequeña, más importante: confiar en el valor predeterminado depende del conocimiento de cada programador para usar alguna vez un código, en cada tipo de datos que viene con un valor predeterminado. (¿DateTime?)

En serio, creo que esto es muy extraño: el mismo programa que debería protegerte de cometer todos los errores demasiado obvios, está sugiriendo aquí para hacer uno, solo para un mayor rendimiento? (Estamos hablando de código de inicialización aquí, solo ejecutado una vez! Los programadores que se preocupan mucho, por supuesto pueden omitir la inicialización (y probablemente deberían usar C o ensamblador :-)).

¿FxCop está cometiendo un error obvio aquí, o hay más que eso?

dos actualizaciones:

  1. Esto no es sólo mi opinión, pero lo que me han enseñado en la universidad (Bélgica). No es que me guste usar un argumentum ad verecundiam, pero solo para mostrar que no es solo mi opinión . Y en cuanto a que:

  2. Mis disculpas, acabo de encontrar esta:

    Should I always/ever/never initialize object fields to default values?

+0

No creo que haya siquiera un beneficio de rendimiento al omitir la inicialización. –

+0

Estoy de acuerdo con Martinho, pero me gusta su pregunta! –

+1

@Martinho Fernandes: Existe un beneficio en el rendimiento al omitir esto: ver mi respuesta y el artículo al que se hace referencia. –

Respuesta

12

No puede haber importantes ventajas de rendimiento a partir de esto, en algunos casos. Para más detalles, see this CodeProject article.

El problema principal es que no es necesario en C#. En C++, las cosas son diferentes, por lo que muchos profesores enseñan que siempre debe inicializar. La forma en que se inicializan los objetos ha cambiado en .NET.

En .NET, los objetos siempre se inicializan cuando se construyen. Si agrega un inicializador, es posible (típico) que cause una doble inicialización de sus variables. Esto sucede ya sea que los inicialices en el constructor o en línea.

Además, dado que la inicialización no es necesaria en .NET (siempre ocurre, incluso si no indica explícitamente inicializar a la predeterminada), agregar un inicializador sugiere, desde el punto de vista de la legibilidad, que está tratando de agregar código que tiene una función. Cada fragmento de código debe tener un propósito o eliminarse si no es necesario. El código "adicional", incluso si era inofensivo, sugiere que está ahí por una razón, lo que reduce la capacidad de mantenimiento.

+2

innecesario para quién o qué? Por supuesto, código para personas, para los comentarios de una máquina son innecesarios también, esto no significa que no son necesarios. – Peter

+0

Puede ponerlo como un comentario, tan fácil como una declaración, y no crear los mismos impactos de rendimiento. Es como tener un código que es inalcanzable; puede proporcionarte algo, pero prefiero tenerlo como comentario que dejar el código inalcanzable en mis métodos. –

+1

La diferencia con un comentario, es cuando digo int i = 0; Quiero que sea cero, la declaración es lógica. Incluso cuando se compila con un compilador futuro que tiene otros valores predeterminados (poco probable por supuesto) – Peter

2

No depende de que cada programador conozca algún "estándar corporativo" definido localmente que pueda cambiar en cualquier momento, sino en algo formalmente definido en el Estándar. También podría decir "no use x++ porque eso depende del conocimiento de cada programador.

+0

problemas completamente diferentes imo, (entre() tiene DateTime a valor predeterminado, y cuál es su valor? Lo que hace x-- do? Creo que la respuesta a este último 100% de los programadores sabe, la respuesta a la primera - si tenemos suerte - 50%) – Peter

+0

En primer lugar, es igual a "predeterminado (DateTime)". En segundo lugar, ¿bajo qué circunstancias te importaría cuál es el valor real? –

2

Debe recordar que las reglas de FxCop son solo pautas, no son irrompibles. Incluso se dice en la página de la descripción de la regla que usted ha mencionado (http://msdn.microsoft.com/en-us/library/ms182274(VS.80).aspx, el énfasis es mío):

Cuando para excluir advertencias:

Excluir una advertencia de esta regla si el constructor llama a otro constructor en la misma o clase base que inicializa el campo a un valor no predeterminado. También es seguro excluir una advertencia de esta regla, o deshabilitar la regla por completo, si el rendimiento y el mantenimiento del código no son prioridades.

Ahora, la regla no es del todo incorrecta, pero como dice, esta no es una prioridad para usted, así que simplemente deshabilite la regla.

3

FX Cop lo ve como agregar código innecesario y el código innecesario es malo. Estoy de acuerdo contigo, me gusta ver en qué está configurado, creo que lo hace más fácil de leer.

Un problema similar que encontramos es, por razones de documentación podemos crear un constructor vacío como esto

/// <summary> 
/// a test class 
/// </summary> 
/// <remarks>Documented on 4/8/2009 by richard</remarks> 
public class TestClass 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="TestClass"/> class. 
    /// </summary> 
    /// <remarks>Documented on 4/8/2009 by Bob</remarks> 
    public TestClass() 
    { 
     //empty constructor 
    }   
} 

El compilador crea este constructor automáticamente, por lo FX policía se queja pero nuestras reglas de documentación de castillos de arena requiere que todos los métodos públicos a documentarse, así que le pedimos a FX Police que no se queje.

+0

código innecesario es malo, por supuesto, pero este código puede ser necesario en el caso improbable de que un defecto se modifique en el futuro y este código se vuelva a compilar. – Peter

+0

@ Peter: los valores predeterminados para los tipos de valores están garantizados para inicializarse siempre en ceros. Es parte de la especificación CLR en sí misma. No hay forma de que un tipo de valor predeterminado cambie. Los tipos de referencia son los mismos: están garantizados, por especificación, por defecto a nulo. –

+0

@Bob ¡El conserje, haciendo cosas que no se sienten bien solo para satisfacer una herramienta, generalmente termina mal! ;) –

5

FxCop tiene que proporcionar reglas para todos, por lo tanto, si esta regla no le resulta atractiva, simplemente excluyala.

Ahora, sugeriría que si desea declarar explícitamente un valor predeterminado, use una constante (o variable de solo lectura estática) para hacerlo. Será incluso más claro que inicializar con un valor, y FXCop no se quejará.

private const int DEFAULT_AGE = 0; 

private int age = 0; // FXCop complains 
private int age = DEFAULT_AGE; // FXCop is happy 

private static readonly DateTime DEFAULT_BIRTH_DATE = default(DateTime); 

private DateTime birthDate = default(DateTime); // FXCop doesn't complain, but it isn't as readable as below 
private DateTime birthDate = DEFAULT_BIRTH_DATE; // Everyone's happy 
+0

tx (también se sugirió en un comentario anterior) – Peter

5

Reed Copsey said especificar valores predeterminados para un rendimiento campos impactos, y se refiere a a test from 2005.

public class A 
{ 
    // Use CLR's default value 
    private int varA; 
    private string varB; 
    private DataSet varC; 
} 

public class B 
{ 
    // Specify default value explicitly 
    private int varA = 0; 
    private string varB = null; 
    private DataSet varC = null; 
} 

Ahora ocho años y cuatro versiones de C# y .NET después decidí repetir esa prueba en .NET Framework 4.5 y C# 5, realizado con el lanzamiento con las optimizaciones por defecto utilizando Visual Studio 2012. Me sorprendió ver que todavía hay una diferencia de rendimiento entre inicializar campos explícitamente con sus valores predeterminados y no especificar un valor predeterminado. Hubiera esperado que los compiladores posteriores de C# optimizaran esas asignaciones constantes de distancia ahora.

 
No init: 512,75 Init on Def: 536,96 Init in Const: 720,50 
Method No init: 140,11 Method Init on Def: 166,86 

(the rest)

Por lo tanto, se asomó a los constructores de las clases A y B en esta prueba, y tanto están vacías:

.method public hidebysig specialname rtspecialname 
    instance void .ctor() cil managed 
{ 
    // Code size 7 (0x7) 
    .maxstack 8 

    IL_0000: ldarg.0 
    IL_0001: call instance void [mscorlib]System.Object::.ctor() 
    IL_0006: ret 
} // end of method .ctor 

pude no encontrar un motivo en el IL por qué la asignación explícita de valores constantes por defecto a los campos contaría sume más tiempo. Aparentemente el compilador de C# hace optimizar las constantes de distancia, y sospecho que siempre lo hizo.

Entonces, la prueba debe estar equivocada ... Cambié el contenido de las clases A y B, cambié los números en la cadena de resultados y repasé las pruebas. Y lo y behold ahora de repente especificando los valores predeterminados es más rápido.

 
No init: 474,75 Init on Def: 464,42 Init in Const: 715,49 
Method No init: 141,60 Method Init on Def: 171,78 

(the rest)

Por lo tanto, mi conclusión es que el compilador de C# optimiza correctamente para el caso en que se asignan valores predeterminados a los campos. ¡No hace diferencia en el rendimiento!


Ahora sabemos el rendimiento es realmente no un problema. Y estoy de acuerdo con Reed Copsey's statement "El código 'extra', incluso si era inofensivo, sugiere que está ahí por una razón, lo que reduce la capacidad de mantenimiento." Y de acuerdo con Anders Hansson en esto:

pensar a largo plazo mantenimiento.

  • Mantenga el código tan explícito como sea posible.
  • No confíe en las formas específicas de idioma para inicializar si no es necesario. ¿Tal vez una versión más nueva del lenguaje funcionará de manera diferente?
  • Los futuros programadores se lo agradecerán.
  • La dirección se lo agradecerá.
  • ¿Por qué ofuscar las cosas siquiera la más mínima?

Los futuros mantenedores pueden provenir de un entorno diferente. Realmente no se trata de lo que es "correcto" sino de lo que será más fácil a largo plazo.

Cuestiones relacionadas