2016-12-28 77 views
7

我宣佈這樣一個元組:F#元組恆從未初始化

module MyModule = 
    let private INVALID_TUPLE = ("0", DateTime.MinValue) 

當我引用它較低的模塊中,它總是空:

let private invalidForNone someOtherTuple = 
    match someOtherTuple with 
    | None -> INVALID_TUPLE // it's null 
    | Some(t) -> t 

此外,當我把一個元組聲明中的斷點,它從來沒有命中。

如果我做一個腳本(FSX)文件完全一樣的東西,開始調試,運行,在元組聲明命中斷點和參考元組是不錯的。

ILSpy我的模塊顯示,有產生了一些啓動代碼具有創建INVALID_TUPLE一個主要方法。顯然,這是不是由於某種原因運行?

這裏是再現行爲(現在我知道它是與MSTest的執行代碼的方式)的樣品。從C#單元測試中調用它;結果將爲空。事實上,F#代碼中沒有任何斷點將會執行。通過從庫中引用它,或者使用單元測試亞軍 - 例如,當您運行編譯爲在不運行編譯可執行文件的Main法的方式進行的可執行代碼都可能發生

module NullTupleTest 
open System 

let private INVALID_TUPLE = ("invalid", DateTime.MinValue) 

let private TupleTest someTuple = 
    match someTuple with 
    | None -> INVALID_TUPLE 
    | Some(dt) -> dt 

let Main = TupleTest None 
+0

你怎麼知道它是空的?某個地方實際上不起作用嗎? –

+0

好的,我得到一個NRE下游,我也知道它是空的,因爲調試器告訴我這樣。 – dudeNumber4

+0

調試器不可靠。不要依賴它。你能說明你在哪裏得到NRE,以及這個所謂的空值是如何到達那裏的?或者提供另一個最小可重現的例子?另請參閱「[如何提出一個好問題](http://stackoverflow.com/help/how-to-ask)」。 –

回答

7

錯誤。解決方案是將F#項目編譯爲一個庫,並可能有另一個可執行文件作爲入口點。 (或者,你也可以修改代碼以避免let約束全局值,但我更喜歡第一種方法。)

這是由F#編譯器的編譯爲可執行代碼和不同的方式處理初始化造成的事實用於編譯爲庫的代碼。

  • 對於庫,初始化代碼被置於靜態構造,當該字段被訪問的第一次
  • 對於可執行文件,初始化代碼被放入Main方法,該方法被執行並且在運行時的應用程序啓動(但只有當它作爲普通可執行文件啓動時)。

我想這樣做的原因是,F#編譯器試圖保持在初始化發生(從上到下)的順序。對於可執行文件,可以通過運行Main方法中的初始化程序來完成此操作。對於圖書館來說,沒有可靠的方法來做到這一點(因爲圖書館沒有「初始化」),所以使用靜態構造函數是次佳選擇。