重载构造函数,无需初始化

时间:2011-10-25 15:32:54

标签: f#

我正在编写一个包含两个构造函数的泛型类:第一个初始化每个字段,第二个(无参数)不应该初始化任何字段。

我发现实现此目的的唯一方法是使用“空”参数调用主构造函数,即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#中存在这样的东西吗?)
  • 使用不同的语法来指定构造函数和私有字段(如何?)

实现此课程的最佳方法是什么?

2 个答案:

答案 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#中同样处理这两种情况。