F#中的多个构造函数和类继承

时间:2014-12-01 13:11:39

标签: f#

我很难将以下C#代码转换为F#:

class Foo
{
    public Foo() { }
    public Foo(string name) { }
}

class Bar : Foo
{
    public Bar() : base() { }
    public Bar(string name) : base(name) { }
    public string Name { get; set; }
}

我首先尝试过关注,但报告错误

  

“Bar”类型的构造函数必须直接或间接调用它   隐式对象构造函数。使用对隐式对象的调用   构造函数而不是记录表达式。

type Foo() =
    new(name:string) = Foo()

type Bar() =
    inherit Foo()
    new(name:string) = { inherit Foo(name) }
    member val Name:string = null with get, set

然后我尝试了关注,但它现在报告了自动属性

的错误
  

'member val'定义仅允许在具有primary的类型中   构造函数。考虑为您的类型定义“

添加参数
type Foo() =
    new(name:string) = Foo()

type Bar =
    inherit Foo
    new(name:string) = { inherit Foo(name) }
    member val Name:string = null with get, set

3 个答案:

答案 0 :(得分:7)

如果您希望F#源代码编译为与C#代码给出的完全相同的 API,答案如下:

type Foo =
    new() = {}
    new(name:string) = { }

type Bar =
    inherit Foo

    [<DefaultValue>] 
    val mutable private name:string

    new() = { inherit Foo() }
    new(name) = { inherit Foo(name) }

    member x.Name with get() = x.name and set v = x.name <- v

答案 1 :(得分:1)

编译:

type Foo() =
    new(name:string) = Foo()

type Bar(name : string) =
    inherit Foo()
    new() = Bar(null) // or whatever you want as a default.
    member val Name:string = name with get, set

请参阅 Constructors (F#) Inheritance (F#)

查看反编译,C#将(删除属性):

public class Bar : Program.Foo {
    internal string Name@;

    public string Name {
        get {
            return this.Name@;
        }
        set {
            this.Name@ = value;
        }
    }

    public Bar(string name) {
        this.Name@ = name;
    }

    public Bar() : this(null) {
    }
}

public class Foo {
    public Foo() {
    }

    public Foo(string name) : this() {
    }
}

答案 2 :(得分:1)

如果某个类的名称后面有一个参数列表(包括()),则它有一个主构造函数。使用它,任何inherit声明都只放在这个主构造函数中,它直接在类声明之后和任何member声明之前。

目前还不清楚你想要实现的目标。类Foo有一个带字符串参数的构造函数,只是为了丢弃它。一个(技术上)有效的,类似的一对类将是这样的:

type Foo(name:string) =
    member f.NameLength = name.Length

type Bar(initialName) = // WARNING: this will not end well
    inherit Foo(initialName)
    member val Name:string = initialName with get, set

但这不是合理的代码。 Foo将保留初始名称,即使Bar中的名称已更改。 Bar.Name.Length返回当前名称的长度,而Bar.NameLength返回初始名称的长度。

要保留默认构造函数,可以添加new () = Bar(null)(或Foo中的等效项),但请注意 null被视为仅限互操作功能。它不用于F#面向代码;如果可能的话,分别使用适当的选项类型或空字符串(取决于字符串是空的还是根本不存在)。

此外,在F#组件设计指南中不鼓励继承类 - 这是有充分理由的。用例很少,但那些通常涉及一个很小的基类和派生类,它是它的完美超集。通过使用一个类作为另一个类的成员来组合类型更为常见。


我不知道这是多么相关,但这里是一个带有默认构造函数的类和一个使用它的附加构造函数的示例:

type Text500(text : string) =
    do if text.Length > 500 then
        invalidArg "text" "Text of this type cannot have a length above 500."
    member t.Text = text
    new () = Text500("")

这利用主构造函数来验证输入,并且有一个使用空字符串的附加无参数构造函数。 (我不确定额外的构造函数在实际应用程序中是否有用。)