【问题标题】:Static constructors in F# - when do they run?F# 中的静态构造函数 - 它们何时运行?
【发布时间】:2017-01-14 15:30:49
【问题描述】:

我正在尝试在 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 课程并不像我想象的那么急切。它的静态构造函数只在我第一次尝试访问实例时运行,而我认为静态类构造函数会在程序启动时运行。

我想我没有太多问题了,除了问:这是否记录在任何地方?我错过了哪些关于何时运行类的静态构造函数的文档?

【问题讨论】:

    标签: constructor static f# singleton lazy-loading


    【解决方案1】:

    我设法在官方 F# 文档中找到了答案,因为http://fsharpforfunandprofit.com 是一个非常棒的资源,所以我很少再看它了。但是官方 F# 文档中的 Constructors article 说(强调我的):

    除了指定用于创建对象的代码外,静态letdo 绑定可以在类类型中编写,这些类型在第一次使用类型之前在类型级别执行初始化。

    let Bindings in Classesdo Bindings in Classes 文章的后续链接,上面写着(再次强调我的):

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

    类定义中的do 绑定在构造对象时执行操作,或者对于静态do 绑定,在第一次使用该类型时

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

    【讨论】:

    • 这意味着我的 Lazy 类并没有太多意义:Eager 类仅在第一次使用时才被实例化,因此使用 Instance.Value 的额外循环似乎没有获得任何东西。因此,最好走简单的路线。
    • 有趣的帖子,所以如果我理解正确的话,第一个和第三个引号之间的区别在于initialization 与执行操作(副作用,例如 printfn)。解决时间上的差异:第一次使用类型之前 vs 第一次使用类型时
    • @rmunn 请注意,这实际上不是“第一次使用该类时”,而是“使用该类之前的某个时间”。何时调用该初始化阶段取决于运行时。唯一的保证是它会在使用类型之前发生。
    猜你喜欢
    • 2012-03-09
    • 2022-07-07
    • 2020-02-15
    • 1970-01-01
    • 2011-07-15
    • 2011-05-06
    • 2020-05-05
    • 2023-03-29
    • 2011-03-01
    相关资源
    最近更新 更多