rksoftware

Visual Studio とか C# とかが好きです

C# 9.0 の確認「モジュール初期化子」

C# 9.0 の確認の目次はこちら

■ モジュール初期化子

ドキュメントはこちら

コード ジェネレーターのサポート という項目の 4 つ目の塊 「コード ジェネレーターの 2 つ目の新機能は」 から始まるブロックです。
簡単に言うとアセンブリ (.dll) が使われる際の初期化メソッドを実装できます。

これまでは、クラスライブラリなどで初期化が必要な場合は、初期化用のメソッドを用意して利用側で最初に一回呼び出すなどのルールでやっていたりしました。
ルールというのは危険で、簡単に守られない事態に遭遇します。守らなくてはならないものをルールにしておくのは悪手です。守らなければならないものは仕組みで守るべきです。そのための仕組みができました。

■ モジュール初期化

こんな感じです。

using System;
using System.Runtime.CompilerServices;

namespace ClassLibrary
{
    public class Class1
    {
        public static string Saitama => "Saitama! Saitama!";
    }

    class Class2
    {
        [ModuleInitializer]
        internal static void Initialize1() => Console.WriteLine("Initialize1");

        [ModuleInitializer]
        internal static void Initialize2() => Console.WriteLine("Initialize2");
    }
}

ModuleInitializer 属性のついているメソッドが初期化メソッドです。今回は 2 つ用意してみました。ほかにもいくつかルールがありますが、それはドキュメントを見てください。概ね何の前提もなくこのメソッドがただ呼ばれる、という前提で考えればいいでしょう。呼び出し元で何もしない、つまりパラメータも渡さない (型パラメータも渡さない)、クラスのインスタンスも生成しない、戻り値も使わない。そう考えておけばルールは覚えておかなくても大丈夫でしょう。

■ 検証コードと結果

■ クラスライブラリを使う側のコード

前述のコードで作ったクラスライブラリをコンソールアプリから使ってみます。

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Method();
        }

        static void Method()
        {
            Console.WriteLine(ClassLibrary.Class1.Saitama);
        }
    }
}

クラスライブラリの中の Initialize1Initialize2 の 2 つのメソッドは呼び出していません。

■ 実行結果

Hello World!
Initialize1
Initialize2
Saitama! Saitama!

計画通り! 初期化のメソッドが実行されています。

■ まとめ

この機能は、書く必要に出会わない人も少なくはないかもしれません。しかし、ある日レイヤー構造のアーキテクチャを採用したコードを書く日が突然やってくるかもしれません。やってきてほしいです。その時きっと役に立ちます。備えましょう。