F# F中的多构造函数与类继承#
我很难将以下C代码转换为F代码:F# F中的多构造函数与类继承#,f#,F#,我很难将以下C代码转换为F代码: class-Foo { 公共Foo(){} 公共Foo(字符串名){} } 酒吧类别:富 { 公共条():基(){} 公共栏(字符串名称):基(名称){} 公共字符串名称{get;set;} } 我第一次尝试跟踪,但它报告了错误 类型“Bar”的构造函数必须直接或间接调用其 隐式对象构造函数。使用对隐式对象的调用 构造函数而不是记录表达式 然后,我尝试了以下操作,但它现在在自动属性上报告错误 “成员val”定义仅允许在具有主值的类型中使用 构造器。考虑向类型定
class-Foo
{
公共Foo(){}
公共Foo(字符串名){}
}
酒吧类别:富
{
公共条():基(){}
公共栏(字符串名称):基(名称){}
公共字符串名称{get;set;}
}
我第一次尝试跟踪,但它报告了错误
类型“Bar”的构造函数必须直接或间接调用其
隐式对象构造函数。使用对隐式对象的调用
构造函数而不是记录表达式
然后,我尝试了以下操作,但它现在在自动属性上报告错误
“成员val”定义仅允许在具有主值的类型中使用
构造器。考虑向类型定义添加参数“”
这包括:
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
见和
查看反编译,C#将是(删除属性):
公共类栏:Program.Foo{
内部字符串名称@;
公共字符串名{
得到{
返回此.Name@;
}
设置{
this.Name@=值;
}
}
公共栏(字符串名称){
this.Name@=Name;
}
公共栏():此(空){
}
}
公开课Foo{
公共食物({
}
public Foo(字符串名称):this(){
}
}
如果一个类的名称(包括()
)后面直接有一个参数列表,那么它就有一个主构造函数。使用它,任何继承
声明都只放在这个主构造函数中,它直接位于类声明之后和任何成员
声明之前
不清楚您试图实现什么。类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#component设计指南中也不鼓励继承类——这是有充分理由的。虽然用例很少,但这些用例通常涉及一个很小的基类和一个派生类(它是基类的完美超集)。通过将一个类作为另一个类的成员来组合类型要常见得多
我不知道这有多重要,但下面是一个带有默认构造函数的类的示例,以及一个使用它的附加构造函数:
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("")
它利用主构造函数来验证输入,并有一个额外的、无参数的构造函数,该构造函数使用空字符串。(我不确定额外的构造函数在实际应用中是否有用。)如果您希望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
输入Foo=
new()={}
新建(名称:string)={}
铅条=
继承福
[]
val可变私有名称:字符串
new()={inherit Foo()}
new(name)={inherit Foo(name)}
成员x.Name和get()=x.name和set v=x.name谢谢;但这不再是同一个C代码了,对吗?我理解示例C代码不是真正的代码,但问题是看我们是否可以用F#实现精确的逻辑……如果没有其他好的替代方案来解决这个问题,我会在几天内接受你的答案。它确实不太一样(Bar.Name
从string
taking构造函数中获得一个值),但是–IMO–更有意义(如果Name
属性位于基类型中,则意义更大)。对于cour5se,其中的一些差异是反汇编的。IL显示了字段的实现细节。在这种情况下,您仍然无法添加以下内容:带有get的member val Name=null,setYes,我监督了这一点。我编辑了Bar类以包含一个Name属性。它不是一个auto属性,但API和语义完全相同在C#案例中是。没有其他方法可以“不折不扣地”复制您的C#示例。同意;这是目前最接近的解决方法。我遇到了以下编译器错误:没有可用于类型“Foo”的构造函数。
。修复方法是new()={inherit Foo()}
@DharmaTurtle:很高兴它现在对您有效;仅供参考,您提到的这一行已经存在于答案中。我正在尝试使用WPF,我怀疑这里的空构造函数会有所帮助。
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("")
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