c# - 检查一个类是否有显式静态构造函数?

标签 c# reflection ecma

ECMA standard在 $14.5.6.2 下,它指出静态构造函数会影响静态字段初始化顺序。我想要一种方法来强制执行此操作,但无法找到一种方法来检查类型中的显式静态构造函数。如果还没有(并且该类有一些静态字段),C# 运行时似乎会自动生成一个。 是否可以使用反射检查类是否具有显式静态构造函数?

例如 - 下面将在这两种情况下返回一个构造函数,并且我看不出它们之间有任何区别:

static class NoStaticConstructor
{
    public static string Field = "x";
}

static class HasStaticConstructor
{
    static HasStaticConstructor() {}
}

public void Test()
{
    typeof(NoStaticConstructor)
        .GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)
        .ShouldBeEmpty(); // FAILS

    typeof(HasStaticConstructor)
        .GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)
        .ShouldNotBeEmpty(); // SUCCEEDS
}

最佳答案

如果你看generated IL对于这两个类,您将看到它们都有一个静态构造函数:

.method private hidebysig specialname rtspecialname static 
    void .cctor () cil managed 
{ /*...*/ } // end of method HasStaticConstructor::.cctor
.method private hidebysig specialname rtspecialname static 
    void .cctor () cil managed 
{ /*...*/ } // end of method NoStaticConstructor::.cctor

因此,查询构造函数不会对您有帮助,因为无论它是否在 C# 代码中显式编写,它都存在于已编译的代码中。

好消息是,实际上不需要检查构造函数。相反,您应该查找 TypeAttributes.BeforeFieldInit。如前所述here ,默认情况下应用 beforefieldinit 标志,除非该类具有静态构造函数。 为您提供了您正在寻找的有关静态字段初始化顺序的信息。

我们可以编写一个辅助方法来检查:

static bool HasLazyInitialization(Type t) =>
    t.Attributes.HasFlag(TypeAttributes.BeforeFieldInit);

用法:

Console.WriteLine(HasLazyInitialization(typeof(NoStaticConstructor)));  // true.
Console.WriteLine(HasLazyInitialization(typeof(HasStaticConstructor)));  // false.

关于c# - 检查一个类是否有显式静态构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74134653/

相关文章:

c# - 捕获控制台输出以在 VS 中进行调试?

c# - WPF 中的可扩展文本 block

c# - InvalidOperationException:未指定 key 类型。 Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ConfigureSigningCredentials.LoadKey()

Javascript 函数内部的 this 关键字

javascript - JS字符串解构: rest parameter returning inconsistent data

c# - 将存储在整数列表(小端)中的二进制表示形式转换为 Biginteger

grails - 如果包含GORM查询,如何在Grails中将字符串转换为一段代码?

reflection - 如何在 Kotlin 数据类字段上列出(java)注释?

java - 当我不知道它是否预先是 lambda 时,如何安全地代理 lambda?

typescript - 如何将 ES 用户模块(用于渲染器进程)导入 Electron 主进程