我正在创建一个项目,其中有单独的源文件/模块,它们将函数添加到更高级别文件中包含的单个Dictionary中。但是,我发现这些源文件中没有任何内容可以自行评估,即使是不带任何参数/代码甚至不在函数内部的函数。
因此,没有任何内容被添加到词典中。有没有办法强制自动评估模块中的完整函数调用?我将举例说明我正在尝试做的事情:
Registry.fs:
let private functions = Dictionary<string, MessageHandler>()
let add type handler =
functions.Add(type, handler)
Handler1.fs:
Registry.add "type1" (fun m -> ....
)
Handler2.fs:
Registry.add "type2" (fun m -> ....
)
我相信你需要看看this relevant topic。当F#代码被编译为IL时,松散的方法调用将被编译为封闭类型/模块的static
构造函数内的方法调用。这大致相当于下面的C#代码,只是为了看图:
static class Handler1 {
static Handler1() {
// this is the static constructor
Registry.add "type1" ....
}
}
在.NET中,static
构造函数没有被急切地初始化1。这意味着,如果要使.NET运行时调用Handler1
静态构造函数,则需要访问Handler1
类型的静态成员。
在静态上下文中使用类型的示例是
module Handler1 =
[<Literal>]
let Name = "Handler1"
[<EntryPoint>]
let main args =
printf Handler1.Name
上面的代码将强制.NET运行时加载Handler1
类型的静态上下文,如果第一次遇到代码,则会调用静态构造函数。如果您的代码永远不会遇到给定类型的静态上下文(任何静态成员或方法),那么它将永远不会被初始化 - 静态构造函数永远不会被调用。
这种行为是由.NET框架设计的(无论选择何种语言--C#,F#,VB,其他 - 它们都编译为类似的IL)。关键是不要按照从未实际使用过的类型分配不必要的资源。
1在.NET 4之前,当执行代码第一次遇到给定类型时,静态类型上下文被初始化,无论用户代码是与该类型的instace还是静态成员交互。在.NET 4之后,这稍微改变了 - 只有当用户代码与该类型的静态成员交互时,才会初始化静态上下文。