Многократные реализации интерфейса F # с выражениями объекта - PullRequest
5 голосов
/ 31 марта 2020

Согласно документации вы можете реализовать несколько интерфейсов с объектными выражениями. Но если вы видите код ниже:


// Define two interfaces
type IFirst =
  abstract F : unit -> unit
  abstract G : unit -> unit

type ISecond =
  abstract H : unit -> unit
  abstract J : unit -> unit

// This object expression implements both interfaces.
let implementer : IFirst =
    { new ISecond with
        member this.H() = ()
        member this.J() = ()
      interface IFirst with
        member this.F() = ()
        member this.G() = () }

Таким образом, приведение к IFirst вызывает ошибку компилятора. Почему это так?

1 Ответ

5 голосов
/ 31 марта 2020

F # не не выполняет неявные преобразования.

При аннотировании типа в привязке let тип должен строго соответствовать выражению. Например,

let value : obj = new System.Collections.Generic.List<int>()

не удастся скомпилировать, даже если List очень очевидно является объектом.

Когда вы пишете:

let implementer : IFirst = expr 

Тип из expr должно быть абсолютно IFirst. Не существует неявного приведения типа C#.

. Выражение объекта будет иметь свой тип в качестве реализованного абстрактного типа, поэтому:

{ new ISecond with ... }

будет выведено, чтобы иметь тип ISecond. Объедините его с правилом неявного приведения, и у вас будет ошибка компиляции.

Поскольку IFirst и ISecond не связаны, вы можете (во время выполнения) понизить до IFirst:

let firstImplementer = implementer :?> IFirst

Другим вариантом является создание комбинированного интерфейса:

type IBoth = inherit IFirst inherit ISecond

и выполнение:

let implementer =
    {
        new IBoth with ...

Таким образом, вы можете свободно (stati c) обновляться до IFirst или ISecond.

let firstImplementer = implementer :> IFirst
let secndImplementer = implementer :> ISecond
...