11

IL の .NET のインターフェイスで静的コンストラクターを定義できます。ただし、そうすると、インターフェイスでメソッドを実行するときに静的コンストラクターが実行されません。

.method public static void Main() {
    .entrypoint    
    .locals init ( class IInterface cls1 )

    // InterfaceClass static constructor is run
    newobj instance void InterfaceClass::.ctor()
    stloc.0
    ldloc.0
    // IInterface static constructor is not run!!!!!
    callvirt instance int32 IInterface::Method()
    call void [mscorlib]System.Console::WriteLine(int32)
    ret
}

.class public interface IInterface {
    .method private static specialname rtspecialname void .cctor() {
        ldstr "Interface static cctor"
        call void [mscorlib]System.Console::WriteLine(string)
        ret
    }

    .method public abstract virtual instance int32 Method() {}
}

.class public InterfaceClass implements IInterface {

    .method private static specialname rtspecialname void .cctor() {
        ldstr "Class static cctor"
        call void [mscorlib]System.Console::WriteLine(string)
        ret
    }

    .method public specialname rtspecialname instance void .ctor() {
        ldarg.0
        call instance void [mscorlib]System.Object::.ctor()
        ret
    }

    .method public virtual instance int32 Method() {
        ldc.i4.s 42
        ret
    }
}

何が起きてる?CLR 仕様 (Partition II、10.5.3.1) によると、いつ型初期化子が実行されるかは Partition I で指定されていますが、Partition I で型初期化子の実行への参照が見つかりません。

編集:

インターフェイスの静的初期化子を実行することはできますが、静的フィールドをインターフェイスに追加し、コード内のどこかでそのフィールドにアクセスすることによってのみ、フィールドが静的コンストラクターで実際に割り当てられていなくてもかまいません。そのため、インターフェイスでメソッドを呼び出しても静的コンストラクターは実行されないようですが、フィールドにアクセスすると実行されます。これはなぜですか?そして、これは仕様のどこに記載されていますか?

4

1 に答える 1

11

CLI のインターフェイスで .cctor を定義できても、それは役に立たないように思えますパーティション I、§ 8.9.5 は次のように述べています。

BeforeFieldInit とマークされている場合、型の初期化メソッドは、その型に定義された静的フィールドへの最初のアクセス時、またはその前に実行されます。BeforeFieldInit がマークされていない場合、その型の初期化メソッドは次の時点で実行されます (つまり、トリガーされます): その型の静的フィールドへの最初のアクセス、またはその型の静的メソッドの最初の呼び出し、またはインスタンスまたは仮想メソッドの最初の呼び出しそれが値型であるか、その型のコンストラクターの最初の呼び出しである場合は、その型の。 型の初期化メソッドを実行しても、その基本型によって定義された初期化メソッドや、型が実装するインターフェイスの自動実行はトリガーされません。

(強調鉱山)つまり、インターフェイスの型初期化子は自動的に呼び出されません。それを呼び出したい場合は、(IMHO) 次のように、すべての実装クラスで明示的に呼び出す必要があります。

.method private static specialname rtspecialname void .cctor() {
    ldtoken IInterface
    callvirt instance valuetype [mscorlib]System.RuntimeTypeHandle [mscorlib]System.Type::get_TypeHandle()
    call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::RunClassConstructor(valuetype [mscorlib]System.RuntimeTypeHandle)
    ldstr "Class static cctor"
    call void [mscorlib]System.Console::WriteLine(string)
    ret
}
于 2011-03-14T14:50:05.797 に答える