2012-02-08 64 views
6

因此,當我在我的F#代碼中創建一些屬性時,因爲F#不支持自動屬性,據我所知。我必須創建後臺字段並將它們初始化爲null,這在函數式編程術語中似乎不正確。對於例如F#屬性設計

 

let mutable albums : DbSet = null 
let mutable genres : DbSet = null

member x.Albums with get() = albums and set(value) = albums <- value member x.Genres with get() = genres and set (value) = genres <- value

有沒有更好的方法來做到這一點?非常感謝您的建議。

+1

一件事 - 除了打擊墊和TomasPetricek的優秀的答案:如果你真的想成爲「功能性」,那麼我會檢查你需要的類或類 - 的假設就像結構一樣。自動屬性通過將給定類的內部暴露給應用程序的其餘部分來違反良好的信息隱藏。如果你需要一個類的內部暴露給應用程序的其餘部分,那麼也許你並不需要這個類。我想我說的是,如果你真的想從功能上去消除一切必須在課堂上的想法。 – 2012-02-08 11:17:13

+0

噢,還有一件事 - 考慮到您正在處理的內容,您可能會發現此博客文章有用:http://bugsquash.blogspot.com/2011/11/lenses-in-f.html – 2012-02-08 16:25:59

回答

10

F#不支持自動屬性,但它支持一個輕量級的語法時,你只需要一個只讀財產。如果你正在寫一些功能代碼,然後使用只讀性質實際上可能更合適:

type Music(genres : DbSet, albums : DbSet) = 
    member x.Albums = albums 
    member x.Genres = genres 

這是基本相同的墊建議記錄,但它可能是,如果你想有更合適更好地控制類型的外觀(以及它們在C#中的顯示方式或數據綁定方式)。

如果DbSet是一個可變類型,那麼你可能只需要使用上述類型並初始化它一次(你仍然可以修改DbSet的值)。如果你想改變DbSet值,你可以添加返回一個克隆的對象的方法:

member x.WithAlbums(newAlbums) = 
    Music(genres, newAlbums) 

使用null或F#Unchecked.defaultOf<_>被認爲是一個非常不好的做法,你應該總是嘗試創建充分initlized對象。如果該值可能丟失,則可以使用option類型來表示該值,但必須始終爲丟失值編寫處理程序,以使程序安全。

+0

正是我認爲使用null不能被認爲是一種很好的做法,只是爲了這個目的具有明確的選項類型的語言。感謝您的建議。 – netmatrix01 2012-02-08 10:38:09

+0

WPF是否接受選項類型以支持顯式的空值? – Maslow 2015-05-06 15:03:49

5

除非你正在做一些複雜的事情,否則我會建議使用記錄而不是類。基本上,他們是用額外的功能類:不變性,結構相等,模式匹配等:

type Playlists = { 
    Albums: DbSet; 
    Genres: DbSet 
    } 

你可以記錄的領域很容易:

let p = {Albums = ...; Genres = ...} 
let albums = p.Albums 
let genres = p.Genres 

在默認情況下記錄的字段是不可變的;您可以在記錄中聲明可變字段,但這被認爲是不好的做法。儘管您無法設置屬性,但您可以從舊的創建新記錄。默認不變性通常是沒有問題的,而且它使代碼更實用,更容易推理:

let p = {Albums = a; Genres = g} 

    // Create new records by updating one field 
    let p1 = {p with Albums = a1} 
    let p2 = {p with Genres = g2} 

如果你堅持創建類,使用具有明確參數的構造函數建議:

type Playlists(a: DbSet, g: DbSet) = 
    let mutable albums = a 
    let mutable genres = g 
    // ... 

當一個默認的構造函數是必要的,你可以使用Unchecked.default<'T>非可空場,或更好地使用它們的默認構造函數:

// Set fields using dump values 
let mutable albums = new DbSet() 
let mutable genres = new DbSet() 

但請確保在實際使用它們之前設置了這些字段。當你需要一個可變財產

+0

請注意,您可以也可以使記錄的字段以不重要的方式變化。記錄也有一些缺點,例如,您必須顯式設置其所有字段的值才能構建對象。另一個缺點是記錄類型不能繼承,也不能從中派生。 – ShdNx 2012-02-08 10:04:20

+1

確實記錄可以有可變字段。但我認爲這是一個糟糕的設計。當你這樣做時,班級應該是首選。 – pad 2012-02-08 10:07:00

+0

謝謝你的建議。也許我會使用記錄,但在我的情況下,我認爲我對一個物業更感興趣。但我會重新考慮你的建議,看看我是否可以將我的類型設計爲Record。 – netmatrix01 2012-02-08 10:41:49

5

僅供參考 - 自動屬性計劃用於F#3.0。請參閱preview documentation [MSDN]。看起來像你的例子將成爲:

type Music() = 
    member val Albums : DbSet = null with get, set 
    member val Genres : DbSet = null with get, set 
+0

顯然這些東西不允許是私人的 – Maslow 2014-07-28 15:12:50

+0

'member val GroupBox1:GroupBox = new GroupBox()'throws saying'附加信息:對象或值的初始化導致對象或值在其完全遞歸之前被訪問initialized.'這個構造函數似乎在持有auto屬性的構造函數的類之後運行。 – Maslow 2014-07-28 15:22:06

+0

確定他們是:'member val private ...' – Daniel 2014-07-28 15:22:52