用反射评估模块的静态构造函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用反射评估模块的静态构造函数相关的知识,希望对你有一定的参考价值。

我有很多模块,在启动程序时,应该将某些内容添加到更高级别模块中的单个词典中。但是,在编译到Console App时,模块中的表达式和常量似乎被打包到静态构造函数中,因此除非显式引用/当程序认为需要时才会对这些表达式和常量进行求值。

这里有一些关于初始化模块的问题,并且一致认为不可能强制执行。但是,我没有看到他们中的任何人在这方面探讨反思。在C#中我知道你能够调用一个类型的静态构造函数,所以我尝试使用F#模块。

我的尝试涉及向每个模块添加一个自定义属性(MessageHandlerAttribute),其中包含我想在启动程序时评估的表达式,然后运行:

let initAllMessageHandlerModules =
    Assembly.GetExecutingAssembly().GetTypes() 
    |> Array.choose (fun typ -> 
        typ.CustomAttributes 
        |> Seq.tryFind (fun attr -> attr.AttributeType = typeof<MessageHandlerAttribute>)
        |> Option.map (fun _ -> typ))
    |> Array.iter 
        (fun typ -> try typ.TypeInitializer.Invoke(null, null) |> ignore with | ex -> printfn "%A" ex)

但是这给了我以下错误:System.NullReferenceException:对象引用未设置为对象的实例。

我也尝试用这个交换最后的lambda函数:

(fun typ -> try System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typ.TypeHandle) |> ignore with | ex -> printfn "%A" ex)

但这似乎什么都不做。是否有可能实现这一目标?

答案

使用type.GetConstructor而不是type.TypeInitializer。

(fun typ -> try typ.GetConstructor(BindingFlags.Instance ||| BindingFlags.Public, null, CallingConventions.Standard, Array.empty<Type>, Array.empty<ParameterModifier>).Invoke(null, null) |> ignore with | ex -> printfn "%A" ex)

Here是更多的例子

以上是关于用反射评估模块的静态构造函数的主要内容,如果未能解决你的问题,请参考以下文章

静态代码块构造代码块构造函数以及Java类初始化顺序

静态构造函数有啥用?

反射机制

java 反射 如何得到构造函数的参数列表

请教一下C#中父类静态构造函数在子类中为啥不会和子类的静态构造函数一起执行

Java反射之剖析构造函数