Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Um construtor estático é usado para inicializar quaisquer dados estáticos ou para executar uma ação específica que precisa ser executada apenas uma vez. Ele é chamado automaticamente antes que a primeira instância seja criada ou quaisquer membros estáticos sejam referenciados. Um construtor estático é chamado no máximo uma vez.
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}
Há várias ações que fazem parte da inicialização estática. Essas ações têm lugar pela seguinte ordem:
- Os campos estáticos são definidos como 0. O ambiente de execução normalmente faz essa inicialização.
- Os inicializadores de campo estático são executados. Os inicializadores de campo estático no tipo mais derivado são executados.
- Executam-se os inicializadores de campos estáticos do tipo base. Inicializadores de campos estáticos, começando com a base direta, passando por cada tipo de base até System.Object.
- Qualquer construtor estático executa. Os construtores estáticos, desde a classe base mais geral até o tipo, executam passando por cada classe base através de Object.Object. A ordem de execução do construtor estático não é especificada. No entanto, todos os construtores estáticos na hierarquia são executados antes de qualquer instância ser criada.
Importante
Há uma exceção importante à regra de que um construtor estático é executado antes de qualquer instância ser criada. Se um inicializador de campo estático cria uma instância do tipo, esse inicializador é executado (incluindo qualquer chamada para um construtor de instância) antes que o construtor estático seja executado. Isso é mais comum no padrão singleton, conforme mostrado no exemplo a seguir:
public class Singleton
{
// Static field initializer calls instance constructor.
private static Singleton instance = new Singleton();
private Singleton()
{
Console.WriteLine("Executes before static constructor.");
}
static Singleton()
{
Console.WriteLine("Executes after instance constructor.");
}
public static Singleton Instance => instance;
}
Um inicializador de módulo pode ser uma alternativa a um construtor estático. Para obter mais informações, consulte a especificação para inicializadores de módulo.
Observações
Os construtores estáticos têm as seguintes propriedades:
- Um construtor estático não usa modificadores de acesso ou tem parâmetros.
- Uma classe ou struct só pode ter um construtor estático.
- Construtores estáticos não podem ser herdados nem sobrecarregados.
- Um construtor estático não pode ser chamado diretamente e destina-se apenas a ser chamado pelo Common Language Runtime (CLR). É invocado automaticamente.
- O usuário não tem controle sobre quando o construtor estático é executado no programa.
- Um construtor estático é chamado automaticamente. Ele inicializa a classe antes que a primeira instância seja criada ou quaisquer membros estáticos declarados nessa classe (não suas classes base) sejam referenciados. Um construtor estático é executado antes de um construtor de instância. Se inicializadores de variáveis de campo estático estiverem presentes na classe do construtor estático, eles serão executados na ordem textual em que aparecem na declaração de classe. Os inicializadores são executados imediatamente antes do construtor estático.
- Se você não fornecer um construtor estático para inicializar campos estáticos, todos os campos estáticos serão inicializados com seu valor padrão, conforme listado em Valores padrão de tipos C#.
- Se um construtor estático lançar uma exceção, o tempo de execução não a invocará uma segunda vez e o tipo permanecerá não inicializado durante o tempo de vida do domínio do aplicativo. Mais comumente, uma TypeInitializationException exceção é lançada quando um construtor estático é incapaz de instanciar um tipo ou para uma exceção não tratada que ocorre dentro de um construtor estático. Para construtores estáticos que não estão explicitamente definidos no código-fonte, a solução de problemas pode exigir a inspeção do código de linguagem intermediária (IL).
- A presença de um construtor estático impede a adição do atributo de tipo BeforeFieldInit. Isso limita a otimização do tempo de execução.
- Um campo declarado como
static readonlysó pode ser atribuído como parte de sua declaração ou em um construtor estático. Quando um construtor estático explícito não for necessário, inicialize campos estáticos na declaração em vez de através de um construtor estático para melhor otimização do tempo de execução. - O tempo de execução chama um construtor estático não mais do que uma vez num único domínio de aplicação. Essa chamada é feita em uma região bloqueada com base no tipo específico da classe. Não são necessários mecanismos de bloqueio adicionais no corpo de um construtor estático. Para evitar o risco de deadlocks, não bloqueie o thread atual em construtores e inicializadores estáticos. Por exemplo, não aguarde por tarefas, threads, identificadores de espera ou eventos, não adquira bloqueios e não execute operações paralelas que bloqueiam,
Parallel.Invokecomo loops paralelos e consultas LINQ paralelas.
Nota
Embora não seja diretamente acessível, a presença de um construtor estático explícito deve ser documentada para ajudar na solução de problemas de exceções de inicialização.
Utilização
- Um uso típico de construtores estáticos é quando a classe está usando um arquivo de log e o construtor é usado para gravar entradas nesse arquivo.
- Construtores estáticos também são úteis ao criar classes wrapper para código não gerenciado, quando o construtor pode chamar o
LoadLibrarymétodo. - Os construtores estáticos também são um local conveniente para impor verificações em tempo de execução no parâmetro de tipo que não são verificáveis em tempo de compilação através de restrições de parâmetro de tipo.
Exemplo
Neste exemplo, a classe Bus tem um construtor estático. Quando a primeira instância de Bus é criada (bus1), o construtor estático é invocado para inicializar a classe. A saída de exemplo verifica que o construtor estático é executado apenas uma vez, mesmo que duas instâncias de Bus sejam criadas, e que ele é executado antes de o construtor de instância ser executado.
public class Bus
{
// Static variable used by all Bus instances.
// Represents the time the first bus of the day starts its route.
protected static readonly DateTime globalStartTime;
// Property for the number of each bus.
protected int RouteNumber { get; set; }
// Static constructor to initialize the static variable.
// It is invoked before the first instance constructor is run.
static Bus()
{
globalStartTime = DateTime.Now;
// The following statement produces the first line of output,
// and the line occurs only once.
Console.WriteLine($"Static constructor sets global start time to {globalStartTime.ToLongTimeString()}");
}
// Instance constructor.
public Bus(int routeNum)
{
RouteNumber = routeNum;
Console.WriteLine($"Bus #{RouteNumber} is created.");
}
// Instance method.
public void Drive()
{
TimeSpan elapsedTime = DateTime.Now - globalStartTime;
// For demonstration purposes we treat milliseconds as minutes to simulate
// actual bus times. Do not do this in your actual bus schedule program!
Console.WriteLine($"{this.RouteNumber} is starting its route {elapsedTime.Milliseconds:N2} minutes after global start time {globalStartTime.ToShortTimeString()}.");
}
}
class TestBus
{
static void Main()
{
// The creation of this instance activates the static constructor.
Bus bus1 = new Bus(71);
// Create a second bus.
Bus bus2 = new Bus(72);
// Send bus1 on its way.
bus1.Drive();
// Wait for bus2 to warm up.
System.Threading.Thread.Sleep(25);
// Send bus2 on its way.
bus2.Drive();
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Sample output:
Static constructor sets global start time to 3:57:08 PM.
Bus #71 is created.
Bus #72 is created.
71 is starting its route 6.00 minutes after global start time 3:57 PM.
72 is starting its route 31.00 minutes after global start time 3:57 PM.
*/
Especificação da linguagem C#
Para obter mais informações, consulte a seção Construtores estáticos da especificação da linguagem C#.