為什麼 Lazy.CreateFromValue 的行為在 F# 中在 .NET 框架版本之間發生了變化?
在 F# 中編譯這段程式碼時,我剛剛遇到了框架版本之間的行為變化:
let test = Lazy.CreateFromValue 1針對 .NET 框架 2.0 編譯,該表達式會生成一個“已創建”的 Lazy 對象,即:
test.IsValueCreated = true當針對 .NET 框架 4.0 編譯時,表達式會產生一個“未評估”的惰性對象,即:
test.IsValueCreated = false只有在後一種情況下訪問test.Value之後,兩者才是等價的。
我在任何地方都找不到對此更改的任何引用,因此我的問題是為什麼這會表現不同以及更改背後的原因是什麼(它正在破壞)。在我看來,.NET 2.0 中的行為更有意義 - 從具體值創建一個惰性對象應該會導致一個“已經評估”的惰性對象。
在 .NET 4.0 之前,該框架不附帶
Lazy<'T>.那是古老的歷史,但 F# 最初有自己的實現
Lazy,與我們今天的不同 - 你可以在這裡瞥見它。當很明顯
Lazy該框架適合該框架時,該實施就被放棄了。相反,F# 2.0 在程序集中附帶了自己的實現System.Lazy<'T>(注意命名空間)FSharp.Core。這就是您仍然可以在此處看到的實現。其想法是,一旦 .NET 4.0 可用,F# 將從那裡無縫地接上System.Lazy<'T>來,而不會破壞使用者。這在大多數情況下都有效,但並非完全沒有問題。您會注意到 F# 實現有一個
CreateFromValue成員,該成員產生一個Lazy<'T>已標記為已評估類型的值。這在語義上非常有意義,因為您顯然首先給它一個評估值。那麼為什麼 .NET 4.0 實現不做同樣的事情呢?
如果您查看 的文件,
Lazy<'T>您會發現無法在評估狀態下創建它。上面沒有CreateFromValue成員,也沒有建構子取值'T,只有Func<'T>. 實際上是由 F#CreateFromValue作為擴展方法提供的。以非破壞性的方式提供此方法將非常容易:
static member CreateFromValue(value : 'T) : System.Lazy<'T> = let x = System.Lazy<'T>.Create(fun () -> value) x.Value |> ignore x但由於某種原因,這並沒有發生。也許這是一個深思熟慮的選擇——我想你可以支持和反對這種改變——但也許這是一個疏忽。如果你看看這種類型的錯綜複雜的歷史,我想你會同意它可能會更糟。