【问题标题】:Interfaces and abstract classes in F#F# 中的接口和抽象类
【发布时间】:2016-06-07 01:46:53
【问题描述】:

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

到目前为止,我还停留在接口和抽象类上。我遇到的问题:

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

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

感谢所有 cmets、更正、提示等。由于这是我在 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

还有抽象类

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))

【问题讨论】:

    标签: f#


    【解决方案1】:

    抽象类定义不识别接口定义

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

    我不知道如何在抽象类中为接口定义抽象成员

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

    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))
    

    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
    

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

    【讨论】:

    • 感谢您的帮助。我仍然坚持方法的继承和覆盖。抽象类现在定义了member this.NewTrendItem() = null,派生类看起来像type NumberItem() = inherit ValueItem&lt;double&gt;() ...... override this.NewTrendItem() = new NumberItem()。但是,我得到 No abstract or interface member was found that对应于此覆盖错误。
    • 没问题,希望对您有所帮助。我已经更新了评论,以提供一个示例来说明如何做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多