#inheritance #interface #f#
Вопрос:
Когда наследуется несколько интерфейсов, каков правильный способ их реализации в F#?
Например, предположим, что следующая иерархия интерфейса, реализация ITranscript для типа TranscriptNote, дает:
«Значение или конструктор «tservice» не определены».
type TranscriptNote =
{
tservice : Nullable<DateTime>
}
interface ITranscript with
member this.tservice with get() = tservice and set value = tservice <- value
"The value or constructor 'tservice' is not defined."
where ITranscript is :
type ITranscript =
inherit ITablet
abstract member note : byte[] with get
abstract member transcript: string with get
type ITablet =
inherit IParagraph
inherit IInk
type IParagraph =
inherit IEncounter
abstract member paragraphTitle : string with get
abstract member title : string with get
type IEncounter =
abstract member tservice : Nullable<DateTime> with get,set
Заранее благодарю вас за любую помощь.
Ответ №1:
Обновление: у @JL0PD есть правильное объяснение ошибки компилятора, которую вы видите. Я удалил неверную информацию из своего ответа, но оставил остальное.
Один из способов-реализовать каждый интерфейс отдельно. В каждом интерфейсе реализуйте только те элементы, которые явно определены этим интерфейсом:
type IGrandparent =
abstract member GetName : unit -> string
type IParent =
inherit IGrandparent
abstract member GetCount : unit -> int
type MyType() =
interface IGrandparent with
member __.GetName() = "name"
interface IParent with
member __.GetCount() = 1
let obj = MyType() :> IParent
printfn "%A" <| obj.GetName()
printfn "%A" <| obj.GetCount()
Обратите внимание , что я не реализовал GetName
under IParent
, но я все еще могу вызывать GetName
IParent
экземпляр благодаря наследованию.
Ответ №2:
Ваш тип будет выглядеть именно так, если вы хотите скомпилировать его с оригинальной структурой. Но даже если F# поддерживает ООП, это не значит, что это всегда лучший способ, прочитайте руководство по стилю P 3 и 4. F# — это не C# с другим синтаксисом, это другой язык с другими основными принципами. Может быть, ваша иерархия может быть лучше представлена с помощью DU
// [<CLIMutable>] // uncomment this line to make all fields mutable
type TranscriptNote =
{
// instances can be mutated, but only this field
mutable tservice : Nullable<DateTime>
}
interface ITranscript with
// stubs
member _.note = [| |] // empty array
member _.paragraphTitle = "some title"
member _.title = "some another title"
member _.transcript = "some transcript"
member this.tservice with get() = this.tservice // need 'this' to get access to field
and set value = this.tservice <- value
Обратите внимание: вам не нужно реализовывать каждый интерфейс отдельно, но это может помочь в обслуживании.
Комментарии:
1. Это интересно. Вы правы. Я соответствующим образом обновлю свой ответ.