Значения модуля в F# не инициализируются. Зачем?
Я получил странное поведение, когда я использовал F#. Когда я использую let привязки в модуле, и если значение создается из конструктора, то оно неинициализируется при использовании снаружи. (Я использовал его из C#, используя ModuleName.s2 или ModuleName.f())
//in a module
let s1 = "1" //normal
let s2 = new String('i', 5) //null
let f () =
s2.Equals("something") //Exception
Это нормальное поведение? Заранее спасибо.
РЕДАКТИРОВАТЬ: Для целей отладки я хочу скомпилировать его как исполняемый файл. Это может быть проблемой, как указали другие люди.
2 ответа
В библиотеке F# модули инициализируются через статические конструкторы, которые обеспечивают инициализацию до использования любых значений модуля. Напротив, в исполняемом файле F# эта инициализация выполняется в точке входа приложения. Это означает, что если другая сборка ссылается на приложение F# (независимо от языка, на котором написано другое приложение), код инициализации не будет запущен.
ОБНОВИТЬ
Брайан указал мне на эту часть спецификации, которая указывает, что это ожидаемое поведение.
Похоже, что одним из обходных путей может быть предоставление явной точки входа, например:
[<EntryPoint>]
let main _ =
0
Затем вы можете вызвать этот основной метод из своего приложения C#, чтобы убедиться, что содержимое модуля правильно инициализировано.
ОБНОВЛЕНИЕ 2
Я неправильно читал спецификацию - вам не нужно на самом деле вызывать явную точку входа из ссылочной сборки. Его простое присутствие приведет к правильной инициализации.
По какой-то причине SomeModule.s2
реализован как свойство (только для чтения), которое возвращает значение невыразимого статического поля <StartupCode$FS>.$Program.s2@9
, Если вы компилируете как приложение, это поле инициализируется в основном методе. При использовании из вашего кода C# этот метод не вызывается, поэтому поле не инициализируется.
Если вы компилируете как библиотеку, код такой же, за исключением того, что поле инициализируется в статическом конструкторе $Program
класс, поэтому он должен работать при использовании из C#.
Причина s1
всегда работает оптимизация: компилятор F# понимает, что это константа, и реализует f()
как "1".Equals("something")
,