【问题标题】:F# syntax for implementing a 'virtual' property implementing an interface用于实现实现接口的“虚拟”属性的 F# 语法
【发布时间】:2012-10-12 13:59:56
【问题描述】:

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

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

给出以下编译错误

错误 1 ​​成员定义中出现意外的关键字“抽象”。预期的 “成员”、“覆盖”或其他 令牌。 D:\MinorApps\VetCompass\VetCompass\ViewModel\ViewModelBase.fs 18 7 VetCompass

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

我什至不知道从哪里开始索引器!

【问题讨论】:

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


    【解决方案1】:

    所有接口实现都是显式的,这意味着当被视为类的成员时,接口的方法将是私有的。因此,您不能在实现中使用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
    

    【讨论】:

      【解决方案2】:

      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] }
      

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

      【讨论】:

      • 我喜欢对象表达式。它们使游戏脚本编写变得更加容易。
      • 它们还避免了显式接口实现所需的重复和强制转换。
      • 我认为这不适用于我的情况。我的框架(WPF)需要实现接口的类。我认为我不能传递另一个实现 IDataErrorInfo 的类来代替我的视图模型。如果可以使用对象表达式来解决我的问题,那么这不是混合/多重继承,我认为 F# 不允许你这样做吗?不过,对象表达式实际上会在其他地方帮助我,感谢您的发帖。
      【解决方案3】:

      要使用虚拟实现来实现 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)
      

      【讨论】:

        猜你喜欢
        • 2021-11-02
        • 1970-01-01
        • 1970-01-01
        • 2012-06-15
        • 2011-02-13
        • 1970-01-01
        • 1970-01-01
        • 2013-02-27
        • 2011-10-28
        相关资源
        最近更新 更多