CA1810: Inicializar campos estáticos de tipo de referencia insertados

Propiedad Value
Identificador de la regla CA1810
Título Inicializar campos estáticos de tipo de referencia insertados
Categoría Rendimiento
La corrección es problemática o no problemática Poco problemático
Habilitado de forma predeterminada en .NET 8 No

Causa

Un tipo de referencia declara un constructor estático explícito.

Descripción de la regla

Cuando un tipo declara un constructor estático explícito, el compilador Just-In-Time (JIT) agrega una comprobación a cada constructor de instancia y a cada método estático del tipo para asegurarse de que se ha llamado anteriormente al constructor estático. La inicialización estática se desencadena cuando se accede a cualquier miembro estático o cuando se crea una instancia del tipo. Sin embargo, la inicialización estática no se desencadena si declara una variable del tipo, pero no la usa, lo que puede ser importante si la inicialización cambia el estado global.

Cuando todos los datos estáticos se inicializan de forma alineada y no se declara un constructor estático explícito, los compiladores del lenguaje intermedio de Microsoft (MSIL) agregan la marca beforefieldinit y un constructor estático implícito, que inicializa los datos estáticos, en la definición de tipo de MSIL. En la mayoría de los casos, cuando el compilador JIT encuentra la marca beforefieldinit, no se agregan las comprobaciones del constructor estático. Se garantiza que la inicialización estática se produzca en algún momento antes de acceder a los campos estáticos, pero no antes de que se invoque un método estático o un constructor de instancia. Tenga en cuenta que la inicialización estática puede producirse en cualquier momento después de declarar una variable del tipo.

Las comprobaciones del constructor estático pueden reducir el rendimiento. A menudo, un constructor estático se usa únicamente para inicializar campos estáticos, en cuyo caso solo debe asegurarse de que la inicialización estática se produzca antes del primer acceso de un campo estático. El comportamiento beforefieldinit es adecuado para estos y la mayoría de los demás tipos. Solo es inapropiado cuando la inicialización estática afecta al estado global y se cumple una de las siguientes condiciones:

  • El efecto en el estado global es costoso y no es necesario si no se utiliza el tipo.

  • Se puede acceder a los efectos del estado global sin acceder a los campos estáticos del tipo.

Cómo corregir infracciones

Para corregir una infracción de esta regla, inicialice todos los datos estáticos cuando se declara y quite el constructor estático.

Cuándo suprimir las advertencias

Es seguro suprimir una advertencia de esta regla si se aplica uno de los siguientes casos:

  • El rendimiento no es un problema.
  • Los cambios en el estado global que causa la inicialización estática son caros o deben producirse sin excepciones antes de llamar a un método estático del tipo o de crear una instancia del tipo.

Supresión de una advertencia

Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.

#pragma warning disable CA1810
// The code that's violating the rule is on this line.
#pragma warning restore CA1810

Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none del archivo de configuración.

[*.{cs,vb}]
dotnet_diagnostic.CA1810.severity = none

Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.

Ejemplo

En el ejemplo siguiente se muestra un tipo, StaticConstructor, que infringe la regla y un tipo, NoStaticConstructor, que reemplaza el constructor estático por inicialización alineada para cumplir la regla.

public class StaticConstructor
{
    static int someInteger;
    static string? resourceString;

    static StaticConstructor()
    {
        someInteger = 3;
        ResourceManager stringManager =
           new ResourceManager("strings", Assembly.GetExecutingAssembly());
        resourceString = stringManager.GetString("string");
    }

    public void Print()
    {
        Console.WriteLine(someInteger);
    }
}

public class NoStaticConstructor
{
    static int someInteger = 3;
    static string? resourceString = InitializeResourceString();

    static string? InitializeResourceString()
    {
        ResourceManager stringManager =
           new ResourceManager("strings", Assembly.GetExecutingAssembly());
        return stringManager.GetString("string");
    }

    public void Print()
    {
        Console.WriteLine(someInteger);
    }
}
Imports System
Imports System.Resources

Namespace ca1810

    Public Class StaticConstructor

        Shared someInteger As Integer
        Shared resourceString As String

        Shared Sub New()

            someInteger = 3
            Dim stringManager As New ResourceManager("strings",
            System.Reflection.Assembly.GetExecutingAssembly())
            resourceString = stringManager.GetString("string")

        End Sub

    End Class


    Public Class NoStaticConstructor

        Shared someInteger As Integer = 3
        Shared resourceString As String = InitializeResourceString()

        Private Shared Function InitializeResourceString()

            Dim stringManager As New ResourceManager("strings",
            System.Reflection.Assembly.GetExecutingAssembly())
            Return stringManager.GetString("string")

        End Function

    End Class

End Namespace

Observe la adición de la marca beforefieldinit en la definición de MSIL para la clase NoStaticConstructor.

.class public auto ansi StaticConstructor
extends [mscorlib]System.Object
{
} // end of class StaticConstructor

.class public auto ansi beforefieldinit NoStaticConstructor
extends [mscorlib]System.Object
{
} // end of class NoStaticConstructor