Подтвердить что ты не робот

Статический конструктор на интерфейсе .NET не запускается

Вы можете определить статический конструктор на интерфейсе в .NET в IL. Однако, если вы это сделаете, статический конструктор не запускается при запуске метода на интерфейсе:

.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 (раздел II, 10.5.3.1) говорит, что когда инициализаторы типов выполняются, указан в разделе I, но я не могу найти ссылку в разделе я для ввода инициализации.

EDIT:

Я могу запустить статический intitializer интерфейса, но только добавив статическое поле к интерфейсу и получив доступ к этому полю где-нибудь в коде, даже если это поле фактически не назначено в статическом конструкторе. Поэтому кажется, что вызов метода на интерфейсе не приводит к запуску статического конструктора, но доступ к полю делает. Почему это так? И где это упоминается в спецификации?

4b9b3361

Ответ 1

Мне кажется, что даже если вы можете определить .cctor на интерфейсе в CLI, это бесполезно. Раздел 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
}