Freigeben über


Modulinitialisierer

Hinweis

Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.

Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den relevanten Sprachentwurfsbesprechungen (LDM)-Notizen erfasst.

Weitere Informationen zum Einführen von Featurespezifikationen in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.

Champion Issue: https://github.com/dotnet/csharplang/issues/2608

Zusammenfassung

Obwohl die .NET-Plattform über ein Feature verfügt, das das Schreiben von Initialisierungscode für die Assembly (technisch gesehen, das Modul) unterstützt, wird es in C# nicht verfügbar gemacht. Dies ist ein eher Nischenszenario, aber sobald Sie darauf stoßen, scheinen die Lösungen ziemlich schmerzhaft zu sein. Es gibt Berichte über eine Reihe von Kunden (innerhalb und außerhalb von Microsoft), die mit dem Problem kämpfen, und es gibt keinen Zweifel mehr undokumentierte Fälle.

Motivation

  • Ermöglichen Sie Bibliotheken, beim Laden eine einmalige Initialisierung auszuführen, mit minimalem Mehraufwand und ohne dass der Benutzer explizit etwas aufrufen muss.
  • Ein besonderer Punkt der aktuellen static Konstruktoransätze besteht darin, dass die Laufzeit zusätzliche Überprüfungen der Verwendung eines Typs mit einem statischen Konstruktor durchführen muss, um zu entscheiden, ob der statische Konstruktor ausgeführt werden muss oder nicht. Dadurch wird messbarer Aufwand hinzugefügt.
  • Aktivieren sie Quellgeneratoren, um eine globale Initialisierungslogik auszuführen, ohne dass der Benutzer etwas explizit aufrufen muss.

Detailliertes Design

Eine Methode kann als Modulinitialisierer festgelegt werden, indem sie mit einem [ModuleInitializer] Attribut versehen wird.

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

Das Attribut kann wie folgt verwendet werden:

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

Für die Methode, die mit diesem Attribut adressieren soll, gelten einige Anforderungen:

  1. Die Methode muss staticsein.
  2. Die Methode muss parameterlos sein.
  3. Die Methode muss voidzurückgeben.
  4. Die Methode darf nicht generisch sein oder in einem generischen Typ enthalten sein.
  5. Auf die Methode muss über das enthaltende Modul zugegriffen werden kann.
    • Dies bedeutet, dass die effektive Barrierefreiheit der Methode oder internalpublic.
    • Dies bedeutet auch, dass die Methode keine lokale Funktion sein kann.

Wenn eine oder mehrere gültige Methoden mit diesem Attribut in einer Kompilierung gefunden werden, gibt der Compiler einen Modulinitialisierer aus, der jede der zugeordneten Methoden aufruft. Die Aufrufe werden in einer reservierten, aber deterministischen Reihenfolge ausgegeben.

Nachteile

Warum sollten wir dies nicht tun?

  • Möglicherweise reicht die vorhandene Drittanbietertoolerstellung für Initialisierer des Moduls "injizieren" für Benutzer aus, die nach diesem Feature gefragt wurden.

Planungsbesprechungen

8. April 2020