F#中的模块值未初始化。为什么?

时间:2011-07-08 20:06:22

标签: f# module

当我使用F#时,我有一种奇怪的行为。 当我在模块中使用let绑定时,如果值是从构造函数创建的,那么在外部使用时它是未初始化的。 (我使用ModuleName.s2或ModuleName.f())从C#中使用它

//in a module
let s1 = "1" //normal
let s2 = new String('i', 5) //null

let f () =
    s2.Equals("something") //Exception

这是正常行为吗?提前谢谢。

编辑: 出于调试的目的,我选择将其编译为可执行文件。这可能是其他人指出的问题。

2 个答案:

答案 0 :(得分:15)

在F#库中,模块通过静态构造函数初始化,这些构造函数确保在使用任何模块的值之前进行初始化。相反,在F#可执行文件中,此初始化在应用程序的入口点中执行。这意味着如果另一个程序集引用了F#应用程序(无论编写其他应用程序的语言如何),将不会运行初始化代码。

<强>更新

布莱恩把我指向this part of the spec,这表明这是预期的行为。

看起来一种解决方法是提供一个明确的入口点,如下所示:

[<EntryPoint>]
let main _ =
    0

然后,您可以从C#app调用此main方法,以确保模块的内容已正确初始化。

更新2

我误读了规范 - 你不需要实际调用引用程序集中的显式入口点。它的存在只会导致初始化正确发生。

答案 1 :(得分:5)

出于某种原因,SomeModule.s2被实现为(只读)属性,该属性返回不可写的静态字段<StartupCode$FS>.$Program.s2@9的值。如果编译为应用程序,则在main方法中初始化该字段。从C#代码中使用时,不会调用此方法,因此不会初始化该字段。

如果您编译为库,代码是相同的,除了在$Program类的静态构造函数中初始化字段,因此它应该在从C#使用时起作用。

s1始终有效的原因是优化:F#编译器将其理解为常量并将f()实现为"1".Equals("something")