F#中的接口和抽象类

use*_*491 5 f#

我正在尝试在F#中创建一小段代码.我的想法是,我将有一个定义一些方法,属性和事件的接口.使用这个接口我想定义一个抽象类(具有泛型类型),它将实现一些属性/方法,但不是所有在接口中定义的成员.定义所有成员的责任在于派生类.

到目前为止,我仍然坚持使用接口和抽象类.我遇到的问题:

  • 抽象类定义无法识别接口定义
  • 我不确定如何为抽象类中的接口定义抽象成员

接口编译正常,但抽象类有几个错误.消息包含在代码中

所有评论,更正,提示等都表示赞赏.由于这是我对F#的第一次试验,可能有很多错误需要指出.

我到目前为止的代码

接口定义

namespace A
    type IValueItem =
        interface    
            [<CLIEvent>]
            abstract member PropertyChanged : 
                Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                              System.ComponentModel.PropertyChangedEventArgs>

            abstract ConvertedX : double with get, set

            abstract Y : double with get, set

            abstract member CreateCopy : obj

            abstract member NewTrendItem : obj
        end
Run Code Online (Sandbox Code Playgroud)

和抽象类

namespace A
    [<AbstractClass>]
    type ValueItem<'TX>() =

        [<DefaultValue>]
        val mutable _y : double

        let _propertyChanged = new Event<_>()

        // ERROR: This type is not an interface type
        // ERROR: The type 'obj' is not an interface type
        // ERROR: The type 'IValueItem' is not defined
        interface IValueItem with

            // ERRROR No abstract or interface member was found that corresponds to this override   
            [<CLIEvent>]
            member this.PropertyChanged : 
                    Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                                    System.ComponentModel.PropertyChangedEventArgs> 
                = _propertyChanged.Publish

            // This definition is incomplete, should be abstract
            member ConvertedX : double with get, set

            // ERROR: Incomplete structured construct at or before this point in pattern
            member CreateCopy() : obj

            member NewTrendItem() : obj

        abstract X : 'TX with get, set

        member this.Y
            with get() = this._y
            and set(value) =
                if this._y <> value then
                    this._y <- value
                    this.NotifyPropertyChanged("Y")

        member this.NotifyPropertyChanged(propertyName) =
                this.PropertyChanged.Trigger(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName))
Run Code Online (Sandbox Code Playgroud)

Mat*_*igh 8

抽象类定义无法识别接口定义

接口必须在抽象类之上声明:在引用的项目/程序集中,在当前文件上方的文件中(文件顺序很重要),或者在同一文件中.

我不确定如何为抽象类中的接口定义抽象成员

不幸的是,我们必须实现接口的所有成员,以保持您希望的行为,您可以让实现调用具有相同签名的类的抽象成员:

type IValueItem =
    [<CLIEvent>]
    abstract PropertyChanged : 
        Control.IEvent<System.ComponentModel.PropertyChangedEventHandler, 
                        System.ComponentModel.PropertyChangedEventArgs>

    abstract ConvertedX : double with get, set

    abstract Y : double with get, set

    abstract CreateCopy : obj

    abstract NewTrendItem : obj

[<AbstractClass>]
type ValueItem<'TX>() =
    let mutable y = 0.0

    let propertyChanged = Event<_, _>()

    interface IValueItem with

        [<CLIEvent>]
        member __.PropertyChanged : Control.IEvent<_, _> = propertyChanged.Publish

        member this.ConvertedX 
            with get() = this.ConvertedX 
            and set(x) = this.ConvertedX <- x 

        member this.CreateCopy = this.CreateCopy
        member this.NewTrendItem = this.NewTrendItem

        member this.Y
            with get() = this.Y 
            and set(y) = this.Y <- y

    abstract ConvertedX : double with get, set
    abstract CreateCopy : obj
    abstract NewTrendItem : obj

    member this.Y
        with get() = y
        and set(value) =
            if y <> value then
                y <- value
                this.NotifyPropertyChanged("Y")

    abstract X : 'TX with get, set

    member this.NotifyPropertyChanged(propertyName) =
        propertyChanged.Trigger(this, System.ComponentModel.PropertyChangedEventArgs(propertyName))
Run Code Online (Sandbox Code Playgroud)

Y属性定义了两次,起初看起来有点奇怪.接口实现遵循类的实现 - 这意味着要访问Y您将不需要将类的实例向上转换为接口,我这样做是为了保持与初始示例相同的行为

你的评论:

要在抽象类上获取虚拟成员,您需要将该成员声明为抽象并提供默认实现,这是一个匹配注释中代码的示例:

type IValueItem =
    abstract NewTrendItem : unit -> obj

[<AbstractClass>]
type ValueItem<'TX>() =
    interface IValueItem with
        member this.NewTrendItem() = this.NewTrendItem()

    abstract NewTrendItem : unit -> obj 
    default __.NewTrendItem() = null

type NumberItem() = 
    inherit ValueItem<double>() 

    override __.NewTrendItem() = new NumberItem() :> obj
Run Code Online (Sandbox Code Playgroud)

通常,OO F#用于与.NET世界的其他部分进行交互 - 这看起来就像这里的情况.但是,如果代码没有与需要OO接口的另一个.NET API进行交互,您可能会发现使用功能方法对问题进行建模可能会产生一些更清晰的代码.F#中的OO可能不会给出该语言的初步良好印象(尽管我个人非常喜欢它的明确性和简洁性)