f# - 使用反射评估模块的静态构造函数
问题描述
我有很多模块,在启动程序时应该将某些内容添加到更高级别模块中的单个字典中。但是,在编译到控制台应用程序时,模块中的表达式和常量似乎被打包到静态构造函数中,因此除非明确引用/当程序认为需要它们时,否则不会对它们进行评估。
这里有一些关于初始化模块的问题,并且一致认为不可能强制。但是,我还没有看到他们中的任何一个在这方面进行过反思。在 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)
这里还有一些例子
推荐阅读
- apache-nifi - Nifi - 在属性中转换以前保存的 now()
- linux - 使用 Google Colab 连接到 Jupyter 笔记本时出现“禁止”错误
- google-bigquery - BigQuery - 对数组求和并排除部分数组
- asp.net-core - Asp.net Core Razor 页面中的引导警报
- objective-c - 查找已调配的方法
- android-studio - 我的每个项目构建错误任务':app:processDebugResources'的执行失败
- haskell - 数字范围之和
- powershell - [Powershell]:第二次执行 Copy-Item 创建子文件夹 (5.1.17763.1007)
- gdb - gdb 堆栈跟踪显示没有回溯 - 所选线程正在运行
- sql-server - 如何在 jdbc 中使用 scope_identity