用于实现实现接口的“虚拟”属性的F#语法

时间:2012-10-12 13:59:56

标签: f# c#-to-f#

我需要在基类中实现IDataErrorInfo接口。该接口需要属性和索引器。我想为两者提供默认实现,并允许子类覆盖它。我似乎无法使用接口实现的语法来实现“虚拟”实现的语法!例如:

type ViewModelBase() =
  interface IDataErrorInfo with
    abstract Error : string with get
    default this.Error with get() = ""

给出以下编译错误

  

错误1成员定义中的意外关键字'abstract'。预期   '成员','覆盖'或其他   令牌。 D:\ MinorApps \ VetCompass \ VetCompass \ ViewModel \ ViewModelBase.fs 18 7 VetCompass

     

错误2此时或之前的结构不完整的构造   模式D:\ MinorApps \ VetCompass \ VetCompass \ ViewModel \ ViewModelBase.fs 19 7 VetCompass

我甚至不确定从索引器开始的位置!

3 个答案:

答案 0 :(得分:6)

所有接口实现都是显式的,这意味着当作为类的成员查看时,接口的方法将是私有的。因此,您无法在实现中使用abstractdefault修饰符。相反,您需要添加一些重复:

type ViewModelBase() =
    // declare a new virtual property
    abstract Error : string
    default this.Error = ""

    interface IDataErrorInfo with
       // pass through to the virtual property implementation
       member this.Error = this.Error

答案 1 :(得分:5)

通常可以使用

Object expressions来代替抽象类和虚方法。您可以通过提供给“工厂”功能的参数来控制行为。像这样:

type IMyInterface =
  abstract SayHello : unit -> string
  abstract Item : string -> obj with get

let makeMyInterface sayHello (lookup: IDictionary<string, obj>) =
  { new IMyInterface with
      member x.SayHello() = sayHello()
      member x.Item 
        with get name = lookup.[name] }

这可能不适用于您的情况,因为您受到现有框架约定的约束。但在某些情况下它可能是一个不错的选择。

答案 2 :(得分:0)

使用虚拟实现来实现IDataErrorInfo和INotifyPropertyChanged是代码:

type ViewModelBase() =
    let propertyChangedEvent = new DelegateEvent<PropertyChangedEventHandler>()

    abstract Error : string with get
    default this.Error with get() = ""

    abstract Item : string -> string with get
    default this.Item with get(name) = ""

    interface INotifyPropertyChanged with
        [<CLIEvent>]
        member x.PropertyChanged = propertyChangedEvent.Publish
    member x.OnPropertyChanged propertyName = 
        propertyChangedEvent.Trigger([| x; new PropertyChangedEventArgs(propertyName) |])

    interface IDataErrorInfo with
       // pass through to the virtual property implementation
       member this.Error = this.Error
       member this.Item with get(x) = this.Item(x)