Condividi tramite


Inizializzatori di modulo

Nota

Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.

Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze sono riportate nelle note pertinenti del linguaggio del language design meeting (LDM).

Altre informazioni sul processo per l'adozione di speclet di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .

Problema del campione: https://github.com/dotnet/csharplang/issues/2608

Sommario

Sebbene la piattaforma .NET abbia una funzionalità che supporta direttamente la scrittura di codice di inizializzazione per l'assembly (tecnicamente, il modulo), non viene esposta in C#. Si tratta di uno scenario piuttosto di nicchia, ma una volta che si entra in esso le soluzioni sembrano essere piuttosto dolorose. Ci sono segnalazioni di un certo numero di clienti (all'interno e all'esterno di Microsoft) che affrontano il problema, e senza dubbio ci sono più casi non documentati.

Motivazione

  • Consentire alle librerie di eseguire un'inizializzazione anticipata e una tantum durante il caricamento, con un overhead minimo e senza che l'utente debba chiamare esplicitamente alcuna funzione.
  • Un particolare punto critico degli approcci del costruttore static corrente è che il runtime deve eseguire controlli aggiuntivi sull'utilizzo di un tipo con un costruttore statico, affinché si decida se il costruttore statico debba essere eseguito o meno. Ciò comporta un sovraccarico misurabile.
  • Abilitare i generatori di origine per eseguire una logica di inizializzazione globale senza che l'utente debba chiamare in modo esplicito alcun elemento

Progettazione dettagliata

Un metodo può essere designato come un inizializzatore di modulo decorato con un attributo [ModuleInitializer].

using System;
namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public sealed class ModuleInitializerAttribute : Attribute { }
}

L'attributo può essere usato come segue:

using System.Runtime.CompilerServices;
class C
{
    [ModuleInitializer]
    internal static void M1()
    {
        // ...
    }
}

Alcuni requisiti vengono imposti al metodo a cui è destinato questo attributo:

  1. Il metodo deve essere static.
  2. Il metodo deve essere senza parametri.
  3. Il metodo deve restituire void.
  4. Il metodo non deve essere generico o essere contenuto in un tipo generico.
  5. Il metodo deve essere accessibile dal modulo contenitore.
    • Ciò significa che l'accessibilità effettiva del metodo deve essere internal o public.
    • Ciò significa anche che il metodo non può essere una funzione locale.

Quando uno o più metodi validi con questo attributo vengono trovati in una compilazione, il compilatore genererà un inizializzatore di modulo che chiama ognuno dei metodi con attributi. Le chiamate verranno generate in un ordine riservato, ma deterministico.

Svantaggi

Perché non farlo?

  • Forse gli strumenti esistenti di terze parti per "iniettare" inizializzatori di modulo sono sufficienti per gli utenti che hanno chiesto questa funzionalità.

Riunioni di progettazione

8 aprile 2020