次の方法で共有


モジュール初期化子

この記事は機能仕様です。 仕様は、機能の設計ドキュメントとして機能します。 これには、提案された仕様の変更と、機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が最終決定され、現在の ECMA 仕様に組み込まれるまで公開されます。

機能の仕様と完成した実装の間には、いくつかの違いがある可能性があります。 これらの違いは、関連する 言語設計会議 (LDM) ノートでキャプチャされます。

機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。

チャンピオン号: https://github.com/dotnet/csharplang/issues/2608

概要

.NET プラットフォームには 機能がありますが アセンブリ (技術的にはモジュール) の初期化コードの記述を直接サポートしますが、C# では公開されません。 これはかなりニッチなシナリオですが、一度それに入ると、ソリューションはかなり痛みを伴うようです。 多くの顧客の報告があります (Microsoft の内部と外部) で問題に苦しんでいます。また、文書化されていないケースは間違いありません。

モチベーション

  • ライブラリが読み込まれたときに一括で 1 回限りの初期化を行えるようにし、オーバーヘッドを最小限に抑え、ユーザーが明示的に何も呼び出す必要がない
  • 現在の static コンストラクターアプローチの特定の問題の 1 つは、静的コンストラクターを実行する必要があるかどうかを判断するために、ランタイムが静的コンストラクターでの型の使用に関する追加のチェックを行う必要があるということです。 これにより、測定可能なオーバーヘッドが追加されます。
  • ユーザーが明示的に何も呼び出さなくても、ソース ジェネレーターでグローバル初期化ロジックを実行できるようにする

詳細な設計

メソッドは、 [ModuleInitializer] 属性で修飾することで、モジュール初期化子として指定できます。

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

属性は次のように使用できます。

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

この属性を対象とするメソッドには、いくつかの要件が課されます。

  1. メソッドは staticする必要があります。
  2. メソッドはパラメーターなしである必要があります。
  3. メソッドは voidを返します。
  4. メソッドをジェネリックにしたり、ジェネリック型に含めたりすることはできません。
  5. メソッドには、包含モジュールからアクセスできる必要があります。
    • つまり、メソッドの有効なアクセシビリティは、 internal または publicする必要があります。
    • これは、メソッドをローカル関数にできないことも意味します。

コンパイルでこの属性を持つ 1 つ以上の有効なメソッドが見つかった場合、コンパイラは、属性付き各メソッドを呼び出すモジュール初期化子を出力します。 呼び出しは予約された決定論的な順序で出力されます。

デメリット

これを行う必要理由

  • おそらく、この機能を要求しているユーザーには、モジュール初期化子を "挿入" するための既存のサード パーティ製ツールで十分です。

デザインに関する会議

2020 年 4 月 8 日