¿Por qué FxCop piensa que la inicialización de campos al valor predeterminado es mala?


Al asignar un valor predeterminado a un campo (aquí false a un bool), FxCop dice:

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 está introduciendo cierta redundancia, pero a mí me parece una muy, muy buena práctica de código, una en la que mis maestros insistieron justamente en mi opinión.

No solo es la penalización de rendimiento muy pequeña, más importante: confiar en el valor predeterminado es confiar en el conocimiento de cada programador para usar una pieza de 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 errores demasiado obvios, está sugiriendo aquí 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 tanto, por supuesto pueden omitir la inicialización (y probablemente deberían usar C o ensamblador :-) ).

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

Dos actualizaciones:

  1. Esta no es solo mi opinión, sino lo que me han enseñado en la universidad (Lgica). No es que me guste usar un argumentum ad verecundiam, pero sólo para mostrar que no es sólo mi opinion. Y sobre eso:

  2. Mis disculpas, acabo de encontrar esta:

    ¿Debo inicializar siempre/siempre / nunca los campos de objeto a valores predeterminados?

 24
Author: Community, 2009-04-08

6 answers

Puede haber beneficios significativos de rendimiento de esto, en algunos casos. Para más detalles, consulte este artículo de CodeProject.

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 se 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 un doble inicialización de sus variables. Esto sucede si los inicializa en el constructor o en línea.

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

 12
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 17:26:41

FxCop tiene que proporcionar reglas para todos, por lo que si esta regla no le atrae, simplemente excluya.

Ahora, sugeriría que si desea declarar explícitamente un valor predeterminado, use una constante (o variable estática de solo lectura) para hacerlo. Será aún 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
 5
Author: Michael Meadows,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 18:17:26

Reed Copsey dijo que especificar valores predeterminados para los campos afecta el rendimiento, y se refiere a una prueba de 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 más tarde decidí repetir esa prueba bajo. NET Framework 4.5 y C# 5, compilado como Versión con optimizaciones predeterminadas utilizando Visual Studio 2012. Me sorprendió ver que todavía hay una diferencia de rendimiento entre inicializar explícitamente los campos con sus valores predeterminados y no especificar un valor predeterminado. Hubiera esperado que los compiladores de C# posteriores optimizaran esas asignaciones constantes a estas alturas.

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

(el resto)

Así que miré dentro de los constructores de las clases A y B en esta prueba, y ambos están vacíos:

.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

Podría no encontrar una razón en el IL por la que asignar explícitamente valores constantes predeterminados a los campos consumiría 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, intercambiado los números en la cadena de resultado, y reran las pruebas. Y he aquí ahora, de repente especificar 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

(el resto)

Por lo tanto, concluyo que el compilador de C# optimiza correctamente para el caso en el que se asignan valores predeterminados a los campos. No hace ninguna diferencia de rendimiento!


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

Piense en el mantenimiento a largo plazo.

  • Mantenga el código lo más explícito posible.
  • No confíes en formas específicas del lenguaje 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 te lo agradecerá.
  • ¿Por qué ofuscar las cosas incluso lo más mínimo?

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

 5
Author: Daniel Pelsmaeker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:29:38

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

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

/// <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 que FX cop se queja, pero nuestras reglas de documentación de castillos de arena requieren que todos los métodos públicos estén documentados, por lo que solo le dijimos a fx cop que no se queje respecto.

 3
Author: Bob The Janitor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 19:07:11

No se basa en 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ías decir " no uses x++ porque eso depende del conocimiento de cada programador.

 2
Author: James Curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 17:28:00

Hay que recordar que las reglas de FxCop son solo directrices, no son irrompibles. Incluso lo dice en la página para la descripción de la regla que mencionaste ( http://msdn.microsoft.com/en-us/library/ms182274 (VS.80).aspx , énfasis mío):

Cuándo excluir Advertencias :

Excluye una advertencia de esta regla si el constructor llama a otro constructor en la misma clase o base que inicializa el campo a un valor no predeterminado. También es seguro excluya una advertencia de esta regla, o deshabilite 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, esto no es una prioridad para usted, así que simplemente deshabilite la regla.

 2
Author: casperOne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-08 17:31:56