F#中的静态构造函数 - 它们什么时候运行?

rmu*_*unn 5 singleton f# static constructor lazy-loading

我正在尝试用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()
Run Code Online (Sandbox Code Playgroud)

这是Lazy.fs:

module TrySingleton.Lazy

type LazyClass() =
    do
        printfn "Initializing lazy class..."

    static do
        printfn "Static constructor of lazy class"

let Instance = lazy LazyClass()
Run Code Online (Sandbox Code Playgroud)

以下是我称之为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
Run Code Online (Sandbox Code Playgroud)

我期望类的静态构造函数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.
Run Code Online (Sandbox Code Playgroud)

似乎这个Eager班级并不像我想象的那样渴望.它的静态构造函数仅在我第一次尝试访问实例时运行,而我认为静态类构造函数将在程序启动时运行.

我想我没有留下太多问题,除了问:这是否记录在任何地方?我想念哪些文档会讨论何时运行类的静态构造函数?

rmu*_*unn 7

我设法在官方F#文档中找到答案,我很少再看,因为http://fsharpforfunandprofit.com是如此优秀的资源.但是官方F#文档中的Constructors文章说(强调我的):

除了指定用于创建对象的代码之外,还可以在类型首次用于在类型级别执行初始化之前执行的类类型中创建静态letdo绑定.

有后续链接到let绑定的类,并do在类绑定的文章,其中说(重点煤矿,再次):

静态let绑定是类的静态初始化程序的一部分,保证在首次使用该类型之前执行.

do对象被构造或时,对于静态的类定义结合执行动作do的结合,当第一次使用的类型.

所以看起来我可以回答我自己的问题:答案是我最初的期望是错误的.静态构造函数将不会必然在程序启动时运行,但只有当该类首先使用.这意味着如果你在两个不同的类中使用Singleton模式,其中一个依赖于另一个,它们的构造函数(和静态构造函数)将按给定依赖关系的顺序运行.(当然,在这种情况下可能有更好,更实用的方法来设计代码;我将其用作说明而不是对该设计的认可.)

  • @rmunn请注意,它实际上不是"在第一次使用类时",而是"在使用类之前的某个时间".由运行时调用初始化阶段决定.唯一的保证是它会在使用该类型之前发生. (2认同)