множественные конструкторы и наследование классов в 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
затем я попытался следовать, но теперь сообщает об ошибке в свойстве auto
определения'member val' разрешены только в типах с первичным конструктор. Рассмотрите возможность добавления аргументов в определение типа"
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 ответов
Если вы хотите исходный код F#, который компилируется в точно так же API как указано в вашем коде C#, ответ выглядит следующим образом:
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
если класс имеет список параметров непосредственно после его имени (включая ()
), имеет главный конструктор. Используя его, любой inherit
объявления размещаются только в этом основном конструкторе, который приходит непосредственно после объявления класса и перед любым member
декларации.
неясно, чего вы пытаетесь достичь. Класс!--5--> имеет конструктор, принимающий строковый аргумент, только чтобы отбросить его. A (технически) действительная, аналогичная пара занятия будут такие:
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("")
это использует основной конструктор для проверки ввода и имеет дополнительный конструктор без параметров, который использует пустую строку. (Я не уверен, что дополнительный конструктор будет полезен в реальных приложениях.)
Это компилирует:
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
посмотреть Конструкторы (F#) и Наследование (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() {
}
}