Compartilhar via


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:

  1. O método deve ser static.
  2. O método deve ser sem parâmetros.
  3. O método deve retornar void.
  4. O método não deve ser genérico nem estar incluído num tipo genérico.
  5. 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 ou public.
    • Isso também significa que o método não pode ser uma função local.

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