rksoftware

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

実行タイミングのわかりにくいコードを書こう! 静的コンストラクター と モジュール初期化子

C# には静的コンストラクターという機能があります。きっと書いたことがある人の方が少ない機能だと思います。
そして、モジュール初期化子というのもあります。こっちはさらに書いたことがある人が少ない機能だと思います。

静的コンストラクター

learn.microsoft.com

モジュール初期化子

learn.microsoft.com

これらを使うと、実行タイミングが分かりにくいコードを書くことができるので、注意が必要です。というか使う必要は普通ないです。
でも、使う必要がないからと言って他人が書かないという保証はありません。いつどんな形でこれらのコードに出会うかわかりません。

備えよう。

■ クラスライブラリのコード

次の 3 つのクラスライブラリがあったとします。

namespace ClassLibrary1;
class Class0
{
    [System.Runtime.CompilerServices.ModuleInitializer]
    internal static void Initialize1() => Console.WriteLine("ClassLibrary1 ModuleInitializer");
}
public class Class1
{
    static Class1() => Console.WriteLine("ClassLibrary1 Class1 static ctor");
    public Class1() => Console.WriteLine("ClassLibrary1 Class1 ctor");
}
namespace ClassLibrary2;
class Class0
{
    [System.Runtime.CompilerServices.ModuleInitializer]
    internal static void Initialize1() => Console.WriteLine("ClassLibrary2 ModuleInitializer");
}
public class Class2
{
    static Class2() => Console.WriteLine("ClassLibrary2 Class2 static ctor");
    public Class2() => Console.WriteLine("ClassLibrary2 Class2 ctor");
}
namespace ClassLibrary3;
class Class0
{
    [System.Runtime.CompilerServices.ModuleInitializer]
    internal static void Initialize1() => Console.WriteLine("ClassLibrary3 ModuleInitializer");
}
public class Class3
{
    static Class3() => Console.WriteLine("ClassLibrary3 Class3 static ctor");
    public Class3() => Console.WriteLine("ClassLibrary3 Class3 ctor");
}

■ これらを使うコード

Console.WriteLine("1");
C c = new();
Console.WriteLine("2");
c.F();
Console.WriteLine("5");
var _ = nameof(ClassLibrary2.Class2);
Console.WriteLine("6");
var type = typeof(ClassLibrary3.Class3);
Console.WriteLine("7");
var ___ = type.FullName;
Console.WriteLine("8");
var ctor = type.GetConstructor(System.Type.EmptyTypes);
Console.WriteLine("9");
ctor?.Invoke(null);
Console.WriteLine("10");

class C
{
    static C() => Console.WriteLine("C static ctor");
    public C() => Console.WriteLine("C ctor");
    public void F()
    {
        Console.WriteLine("3");
        new ClassLibrary1.Class1();
        Console.WriteLine("4");
    }
}

このコードを実行するとどうなるでしょう?

実行結果

ClassLibrary3 ModuleInitializer
1
C static ctor
C ctor
2
ClassLibrary1 ModuleInitializer
3
ClassLibrary1 Class1 static ctor
ClassLibrary1 Class1 ctor
4
5
6
7
8
9
ClassLibrary3 Class3 static ctor
ClassLibrary3 Class3 ctor
10

どうでしょう? 予想通りだったでしょうか?

備えよう

これらのコードはどのクラスにも書けるという特徴があります。いつどんなコードに出会っても慌てないよう備えましょう。