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 则该类型的初始化方法在以下位置执行(即由以下方式触发):首先访问该类型的任何静态字段,或首次调用该类型的任何静态方法,或首次调用任何实例或虚拟方法如果它是值类型或对该类型的任何构造函数的第一次调用,则属于该类型。 任何类型的初始化方法的执行都不会触发其基类型定义的任何初始化方法的自动执行,也不会触发该类型实现的任何接口

(强调我的)这意味着接口上的类型初始化器根本不会被自动调用。如果您希望调用它,您(恕我直言)需要在所有实现类中显式调用它,如下所示:

.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 回答