我正在编写一个包含两个构造函数的泛型类:第一个初始化每个字段,第二个(无参数)不应该初始化任何字段。
我发现实现此目的的唯一方法是使用“空”参数调用主构造函数,即Guid.Empty和null。除了没有为未经训练的眼睛看好的功能风格,这意味着我必须对第二个参数设置a' : null
约束,这是我不想要的:
type Container<'a when 'a : null>(id : Guid, content : 'a) =
let mutable _id = id
let mutable _content = content
new() = Container<'a>(Guid.Empty, null)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
我认为有两种方法可以解决这个问题:
default
c#关键字而不是null(F#中存在这样的东西吗?)实现此课程的最佳方法是什么?
答案 0 :(得分:5)
default
的F#模拟是Unchecked.default<_>
。也可以使用未初始化的显式字段:
type Container<'a>() =
[<DefaultValue>]
val mutable _id : Guid
[<DefaultValue>]
val mutable _content : 'a
new (id, content) as this =
new Container<'a>() then
this._id <- id
this._content <- content
但是,一般来说,你的整体方法对于F#来说有点单一。通常你会使用一个简单的记录类型(可能使用静态方法来创建未初始化的容器,尽管这似乎有可疑的好处):
type 'a Container = { mutable id : Guid; mutable content : 'a } with
static member CreateEmpty() = { id = Guid.Empty; content = Unchecked.defaultof<_> }
在许多情况下,您甚至可以使用不可变记录类型,然后使用记录更新语句生成具有更新值的新记录:
type 'a Container = { id : Guid; content : 'a }
[<GeneralizableValue>]
let emptyContainer<'a> : 'a Container =
{ id = Guid.Empty;
content = Unchecked.defaultof<_> }
let someOtherContainer = { emptyContainer with content = 12 }
答案 1 :(得分:2)
如果类型将使用F#以外的语言,则以下提供F#和C#中的自然界面。
type Container<'a>(?id : Guid, ?content : 'a) =
let orDefault value = defaultArg value Unchecked.defaultof<_>
let mutable _id = id |> orDefault
let mutable _content = content |> orDefault
new() = Container(?id = None, ?content = None)
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
member this.Id
with get() = _id
and set(value) = _id <- value
member this.Content
with get() = _content
and set(value) = _content <- value
如果只使用F#,则可以省略以下构造函数重载
new(id : Guid, content : 'a) = Container<_>(?id = Some id, ?content = Some content)
new() = Container()
因为重载接受可选args在F#中同样处理这两种情况。