F#物业设计

F#物业设计,f#,F#,因此,当我在我的F#代码中创建一些属性时,因为据我所知,F#不支持自动属性。我必须创建支持字段并将它们初始化为null,这在函数式编程术语中似乎不正确。例如 让可变相册:DbSet=null 让可变类型:DbSet=null 成员x.相册 使用get()=相册 和set(value)=albums除非你正在做一些复杂的事情,否则我建议使用记录而不是类。基本上,它们是具有额外特性的类:不变性、结构平等性、模式匹配等: type Playlists = { Albums: DbSet;

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


让可变相册:DbSet=null
让可变类型:DbSet=null

成员x.相册 使用get()=相册
和set(value)=albums除非你正在做一些复杂的事情,否则我建议使用记录而不是类。基本上,它们是具有额外特性的类:不变性、结构平等性、模式匹配等:

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。当需要可变属性时,默认F#不支持自动属性,但当只需要只读属性时,它支持轻量级语法。如果您正在编写一些函数代码,那么使用只读属性实际上可能更合适:

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#中使用
null
未选中。默认的
被认为是一种非常糟糕的做法,您应该始终尝试创建完全初始化的对象。如果该值可能丢失,您可以使用
选项
类型来表示该值,但您必须始终为丢失的值编写处理程序,以确保程序的安全。

FYI-计划为F#3.0提供自动属性。看。看起来您的示例将变成:

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

请注意,您还可以通过简单的方式使记录的字段可变。记录也有一些缺点,例如,为了构造对象,必须显式设置其所有字段的值。另一个缺点是记录类型不能继承,也不能从中派生。记录确实可以有可变字段。但我认为这是一个糟糕的设计。当你这样做的时候,课程应该是首选。谢谢你的建议。也许我应该使用唱片,但就我而言,我想我对一处房产更感兴趣。但我会重新考虑你的建议,看看是否可以将我的类型设计为记录。@pad:我同意这是一种不好的做法,我只是提到了它,因为这个问题已经包含了可变字段,所以我认为这将是相关的信息。@ShdNx:同意,我更新了答案,提到了可变记录字段。我认为使用null不能被认为是一种很好的实践,因为这种语言具有明确的选项类型。谢谢你的建议。WPF是否接受支持显式空值的选项类型?除了Pad和TomasPetricek的优秀答案之外,还有一件事:如果你真的想“功能化”,那么我会首先检查你需要类或类结构的假设。自动属性通过向应用程序的其余部分公开给定类的内部,违反了良好的信息隐藏。如果你需要一个类的内部暴露给应用程序的其余部分,那么也许你一开始就不需要这个类。我想我的意思是,如果你真的想从功能上思考,那么就不要认为所有东西都必须在一个类中。哦,还有一件事——考虑到你所做的工作,你可能会发现这篇博客文章很有帮助:显然这些东西不允许是私有的
member val GroupBox 1:GroupBox=new GroupBox()
抛出
附加信息:对象或值的初始化导致对象或值在完全初始化之前被递归访问。
此构造函数似乎在持有自动属性构造函数的类之后运行。确保它们是:
成员val private…
  member x.WithAlbums(newAlbums) = 
    Music(genres, newAlbums)
type Music() =
  member val Albums : DbSet = null with get, set
  member val Genres : DbSet = null with get, set