Inicializadores de módulo
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Questão campeã: https://github.com/dotnet/csharplang/issues/2608
Resumo
Embora a plataforma .NET tenha um recurso que suporta diretamente a escrita de código de inicialização para o assembly (tecnicamente, o módulo), ele não é exposto em C#. Este é um cenário algo específico, mas uma vez que nos deparamos com ele, as soluções parecem ser um tanto dolorosas. Há relatos de vários clientes (dentro e fora da Microsoft) a lidar com o problema, e sem dúvida há mais casos não documentados.
Motivação
- Permita que as bibliotecas façam uma inicialização única e ágil quando carregadas, com sobrecarga mínima e sem que o usuário precise chamar explicitamente nada
- Um ponto crítico particular das abordagens atuais do construtor
static
é que o tempo de execução precisa realizar verificações adicionais ao utilizar um tipo com um construtor estático, a fim de decidir se o construtor estático precisa ser executado ou não. Isso adiciona despesas gerais mensuráveis. - Permitir que os geradores de origem executem alguma lógica de inicialização global sem que o usuário precise chamar explicitamente nada
Projeto detalhado
Um método pode ser designado como um inicializador de módulo decorando-o com um atributo [ModuleInitializer]
.
using System;
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute { }
}
O atributo pode ser usado assim:
using System.Runtime.CompilerServices;
class C
{
[ModuleInitializer]
internal static void M1()
{
// ...
}
}
Alguns requisitos são impostos ao método visado com este atributo:
- O método deve ser
static
. - O método deve ser sem parâmetros.
- O método deve retornar
void
. - O método não deve ser genérico nem estar incluído num tipo genérico.
- O método deve ser acessível a partir do módulo que o contém.
- Isto significa que a acessibilidade efetiva do método deve ser
internal
oupublic
. - Isso também significa que o método não pode ser uma função local.
- Isto significa que a acessibilidade efetiva do método deve ser
Quando um ou mais métodos válidos com esse atributo são encontrados em uma compilação, o compilador emitirá um inicializador de módulo que chama cada um dos métodos atribuídos. As chamadas serão emitidas numa ordem reservada, mas determinista.
Desvantagens
Porque devemos não fazer isto?
- Talvez as ferramentas de terceiros existentes para "injetar" inicializadores de módulo sejam suficientes para usuários que têm solicitado esse recurso.
Reuniões de design
8 de abril de 2020
C# feature specifications