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

问题描述 投票:1回答:1

我有很多模块,在启动程序时,应该将某些内容添加到更高级别模块中的单个词典中。但是,在编译到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)

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

f# system.reflection static-constructor
1个回答
0
投票

使用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是更多的例子

© www.soinside.com 2019 - 2024. All rights reserved.