我正在尝试用F#创建单身的各种方法,以便更好地理解细微之处。我不知道单身模式在F#中是否有用,但我想进行实验。我对这些单例实例中涉及静态构造函数的一个结果感到惊讶。首先,我会告诉你我的代码,然后我会详细介绍我的问题。
在一个名为TrySingleton
的项目中,我创建了三个模块。这是Eager.fs
:
module TrySingleton.Eager
type EagerClass() =
do
printfn "Initializing eager class..."
static do
printfn "Static constructor of eager class"
let Instance = EagerClass()
这是Lazy.fs
:
module TrySingleton.Lazy
type LazyClass() =
do
printfn "Initializing lazy class..."
static do
printfn "Static constructor of lazy class"
let Instance = lazy LazyClass()
以下是我在Main.fs
中的称呼方式:
module TrySingleton.Main
[<EntryPoint>]
let main argv =
printfn "Starting main with args %A" argv
printfn "Accessing eager instance:"
printfn "%A" Eager.Instance
printfn "Accessing lazy instance:"
printfn "%A" Lazy.Instance.Value
printfn "Accessing eager instance again:"
printfn "%A" Eager.Instance
printfn "Accessing lazy instance again:"
printfn "%A" Lazy.Instance.Value
printfn "Success; exiting."
0
我期望Eager
类的静态构造函数在程序启动时立即运行,并且不确定Lazy
类的静态构造函数何时运行。但是,这是我得到的输出:
Starting main with args [||]
Accessing eager instance:
Static constructor of eager class
Initializing eager class...
TrySingleton.Eager+EagerClass
Accessing lazy instance:
Static constructor of lazy class
Initializing lazy class...
TrySingleton.Lazy+LazyClass
Accessing eager instance again:
TrySingleton.Eager+EagerClass
Accessing lazy instance again:
TrySingleton.Lazy+LazyClass
Success; exiting.
似乎Eager
课程并不像我想象的那样渴望。它的静态构造函数仅在我第一次尝试访问实例时运行,而我认为静态类构造函数将在程序启动时运行。
我想我没有留下太多问题,除了问:这是否记录在任何地方?我想念什么文档,讨论何时运行类的静态构造函数?
答案 0 :(得分:7)
我设法在官方F#文档中找到答案,我很少再看,因为http://fsharpforfunandprofit.com是如此优秀的资源。但官方F#文档中的Constructors article表示(强调我的):
除了指定用于创建对象的代码之外,静态
let
和do
绑定可以在类型首次使用之前执行的类类型中创建以执行初始化类型级别。
有let
Bindings in Classes和do
Bindings in Classes文章的后续链接,这些文章(再次强调我的):
静态
let
绑定是类的静态初始值设定项的一部分,保证在首次使用类型之前执行 。
和
类定义中的
do
绑定在构造对象时执行操作,或者对于静态do
绑定,在首次使用类型时执行 。
所以看起来我可以回答我自己的问题:答案是我最初的期望是错误的。静态构造函数 not 必须在程序启动时运行,但仅在该类首次使用时运行。这意味着如果你在两个不同的类中使用Singleton模式,其中一个依赖于另一个,它们的构造函数(和静态构造函数)将按给定依赖关系的顺序运行。 (当然,在这种情况下可能有更好,更实用的方法来设计代码;我将其用作说明而不是对该设计的认可。)