F# и члены, реализованные в интерфейсе

У меня досадная ошибка.

type Animal =

    abstract member Name : string

type Dog (name : string) =

    interface Animal with

        member this.Name : string =
            name

let pluto = new Dog("Pluto")
let name = pluto.Name

Последняя строка, а именно "Имя", генерирует ошибку компилятора о том, что "поле, конструктор или элемент" Имя "не определены".

Обходной путь, который я использовал, чтобы написать

let name = (pluto :> Animal).Name

Однако это очень раздражает и создает много визуального шума. Есть ли что-то, что можно сделать в F#, чтобы иметь возможность разрешать Name, не сообщая компилятору явно, что Name является производным от типа Animal?

2 ответа

Решение

В F#, когда вы реализуете интерфейс, это эквивалент явной реализации интерфейса в C#. То есть вы можете вызывать метод через интерфейс, но не напрямую через класс.

Справочная статья F# об интерфейсах предлагает добавить метод, который выполняет апкастинг к типу:

type Dog (name : string) =

    member this.Name = (this :> Animal).Name

    interface Animal with
        member this.Name : string = name

Или, как предлагает Даниэль, вы можете сделать это наоборот, что означает, что вы можете избежать этого броска:

type Dog (name : string) =

    member this.Name = name

    interface Animal with
        member this.Name : string = this.Name

Кроме того, соглашение.Net для имен интерфейсов - начинать их с Iпоэтому ваш интерфейс должен называться IAnimal,

Другой вариант - использовать абстрактный интерфейс вместо интерфейса:

[<AbstractClass>]
type Animal () =
    abstract Name : string

type Dog (name) = 
    inherit Animal()
    override dog.Name = name

let pluto = Dog("Pluto")
let name = pluto.Name
Другие вопросы по тегам