В F#, как реализовать интерфейс с родительским и дедушкиным интерфейсами?

#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. Это интересно. Вы правы. Я соответствующим образом обновлю свой ответ.