CA1810: Inicializar campos estáticos de tipo de referência em linha
Property | Valor |
---|---|
ID da regra | CA1810 |
Título | Inicializar campos estáticos de tipo de referência em linha |
Categoria | Desempenho |
Correção interruptiva ou sem interrupção | Sem interrupção |
Habilitado por padrão no .NET 8 | Não |
Causa
Um tipo de referência declara um construtor estático explícito.
Descrição da regra
Quando um tipo declara um construtor estático explícito, o compilador JIT (just-in-time) adiciona uma verificação a cada método estático e construtor de instância do tipo para garantir que o construtor estático tenha sido chamado anteriormente. A inicialização estática é disparada quando qualquer membro estático é acessado ou quando uma instância do tipo é criada. No entanto, a inicialização estática não será disparada se você declarar uma variável do tipo, mas não usá-la, o que pode ser importante se a inicialização mudar o estado global.
Quando todos os dados estáticos são inicializados embutidos e um construtor estático explícito não é declarado, os compiladores de linguagem intermediária comum (CIL) adicionam o beforefieldinit
sinalizador e um construtor estático implícito, que inicializa os dados estáticos, à definição de tipo CIL. Quando o compilador JIT encontra o sinalizador beforefieldinit
, na maioria das vezes, as verificações de construtor estático não são adicionadas. É garantido que a inicialização estática ocorra em algum momento antes de qualquer campo estático ser acessado, mas não antes que um método estático ou construtor de instância seja invocado. Observe que a inicialização estática pode ocorrer a qualquer momento depois que uma variável do tipo é declarada.
As verificações de construtor estático podem diminuir o desempenho. Geralmente, um construtor estático é usado apenas para inicializar campos estáticos. Nesse caso, você só deve verificar se a inicialização estática ocorre antes do primeiro acesso de um campo estático. O comportamento beforefieldinit
é apropriado para esses tipos e para a maioria dos demais tipos. Só será inadequado quando a inicialização estática afetar o estado global e um dos seguintes casos for verdadeiro:
O efeito sobre o estado global é caro e não é necessário se o tipo não for usado.
Os efeitos de estado global podem ser acessados sem acessar nenhum campo estático do tipo.
Como corrigir violações
Para corrigir uma violação dessa regra, inicialize todos os dados estáticos quando declarados e remova o construtor estático.
Quando suprimir avisos
É seguro suprimir um aviso dessa regra se um dos seguintes casos for aplicável:
- O desempenho não for uma preocupação.
- As alterações de estado globais causadas pela inicialização estática forem caras ou quando é necessário garantir que ocorram antes que um método estático do tipo seja chamado ou uma instância do tipo seja criada.
Suprimir um aviso
Para suprimir apenas uma violação, adicione diretivas de pré-processador ao arquivo de origem a fim de desabilitar e, em seguida, reabilitar a regra.
#pragma warning disable CA1810
// The code that's violating the rule is on this line.
#pragma warning restore CA1810
Para desabilitar a regra em um arquivo, uma pasta ou um projeto, defina a severidade como none
no arquivo de configuração.
[*.{cs,vb}]
dotnet_diagnostic.CA1810.severity = none
Para obter mais informações, confira Como suprimir avisos de análise de código.
Exemplo
O exemplo a seguir mostra um tipo StaticConstructor
que viola a regra, e um tipo NoStaticConstructor
que substitui o construtor estático pela inicialização embutida para atender à regra.
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 a beforefieldinit
adição do sinalizador na definição de CIL para a NoStaticConstructor
classe.
.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