Inicializar campos inline estáticos de tipos de referencias
Actualización: noviembre 2007
Nombre de tipo |
InitializeReferenceTypeStaticFieldsInline |
Identificador de comprobación |
CA1810 |
Categoría |
Microsoft.Performance |
Cambio problemático |
No problemático |
Motivo
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 garantizar que se ha llamado previamente al constructor estático. Se desencadena la inicialización estática cuando se tiene acceso a cualquier miembro estático o cuando se crea una instancia del tipo. Sin embargo, no se desencadena la inicialización estática si declara una variable del tipo pero no se utiliza, lo que puede ser importante si la inicialización modifica el estado global.
Cuando se inicializan los datos estáticos en línea y no se declara un constructor estático explícito, los compiladores del lenguaje intermedio de Microsoft (MSIL) agregan un indicador beforefieldinit y un constructor estático implícito a la definición de tipo de MSIL. Cuando el compilador JIT encuentra el indicador beforefieldinit, en la mayoría de los casos no se agregan las comprobaciones de constructor estático. Es seguro que se producirá una inicialización estática en algún momento antes de que se obtenga acceso a los campo estáticos, pero no antes de la invocación de un método estático o un constructor de instancia. Observe 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. Con frecuencia un constructor estático se utiliza sólo para inicializar campos estáticos en los que sólo es necesario asegurarse de que la inicialización estática se produce antes del primer acceso a un campo estático. El comportamiento beforefieldinit es adecuado para éstos y para la mayoría de los otros tipos. No es adecuado sólo cuando la inicialización estática afecta al estado global y una de las siguientes condiciones es verdadera:
El efecto sobre el estado global es costoso y no es necesario si no se utiliza el tipo.
Se puede tener acceso a los efectos sobre el estado global sin tener acceso a cualquier campo estático 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 advertencias
Es seguro suprimir una advertencia de esta regla si el rendimiento no es un aspecto importante, si el estado global cambia debido a que la inicialización estática es costosa o si debe asegurarse de que se produce antes de llamar a un método estático del tipo o de crear una instancia del tipo.
Ejemplo
El siguiente ejemplo muestra un tipo StaticConstructor que infringe la regla, y un tipo NoStaticConstructor, que reemplaza el constructor estático por una inicialización en línea para cumplir la regla.
Imports System
Imports System.Resources
Namespace PerformanceLibrary
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()
Shared Private Function InitializeResourceString()
Dim stringManager As New ResourceManager("strings", _
System.Reflection.Assembly.GetExecutingAssembly())
Return stringManager.GetString("string")
End Function
End Class
End Namespace
using System;
using System.Reflection;
using System.Resources;
namespace PerformanceLibrary
{
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 class NoStaticConstructor
{
static int someInteger = 3;
static string resourceString = InitializeResourceString();
static string InitializeResourceString()
{
ResourceManager stringManager =
new ResourceManager("strings", Assembly.GetExecutingAssembly());
return stringManager.GetString("string");
}
}
}
Tenga en cuenta la suma del indicador 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