F#属性设计

时间:2012-02-08 08:45:51

标签: f#

所以当我在我的F#代码中创建一些属性时,因为F#不支持自动属性,据我所知。我必须创建支持字段并将它们初始化为null,这在函数式编程术语中似乎不正确。对于例如


 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

有没有更好的方法呢?非常感谢你的建议。

3 个答案:

答案 0 :(得分:10)

当您需要可变属性时,F#不支持自动属性,但当您只需要 readonly 属性时,它支持轻量级语法。如果您正在编写一些功能代码,那么使用 readonly 属性可能实际上更合适:

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

这与pad建议的记录基本相同,但如果您希望更好地控制类型的外观(以及它们在C#中的显示方式或数据绑定方式),则可能更合适。

如果DbSet是一个可变类型,那么您可能只需使用上述类型并将其初始化一次(您仍然可以修改DbSet值)。如果要更改DbSet值,可以添加返回克隆对象的方法:

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

在F#中使用nullUnchecked.defaultOf<_>被认为是一种非常糟糕的做法,您应该始终尝试创建完全初始化的对象。如果该值可能丢失,您可以使用option类型来表示该值,但是您必须始终为缺失值编写处理程序,以使您的程序安全。

答案 1 :(得分: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()

但请确保在实际使用之前设置这些字段。

答案 2 :(得分: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