F#中的接口和抽象类

时间:2016-06-04 16:20:42

标签: 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

抽象类

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

1 个答案:

答案 0 :(得分:8)

  

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

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

  

我不确定如何在抽象类

中定义接口的抽象成员

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

public class Class1
{
    public IList<Car> getCarsByProjectionOnSmallNumberOfProperties()
    {

        try
        {
            //Get the SQL Context:
            CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext dbContext 
                = new CompanyPossessionsDAL.POCOContext.CompanyPossessionsContext();

            //Specify the Context of your main entity e.g. Car:
            var oDBQuery = dbContext.Set<Car>();

            //Project on some of its fields, so the created select statment that is
            // sent to the database server, will have only the required fields By making a new anonymouse type
            var queryProjectedOnSmallSetOfProperties 
                = from x in oDBQuery
                    select new
                    {
                        x.carNo,
                        x.eName,
                        x.aName
                    };

            //Convert the anonymouse type back to the main entity e.g. Car
            var queryConvertAnonymousToOriginal 
                = from x in queryProjectedOnSmallSetOfProperties
                    select new Car
                    {
                        carNo = x.carNo,
                        eName = x.eName,
                        aName = x.aName
                    };

            //return the IList<Car> that is wanted
            var lst = queryConvertAnonymousToOriginal.ToList();
            return lst;

        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
            throw;
        }
    }
}

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

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