Reputation: 12258
I need to implement the IDataErrorInfo interface in a base class. The interface requires a property and an indexer. I want to provide a default implementation for both and allow subclasses to override it. I can't seem to wield the syntax for a 'virtual' implementation with the syntax for interface implementation! For example:
type ViewModelBase() =
interface IDataErrorInfo with
abstract Error : string with get
default this.Error with get() = ""
Gives the following compile errors
Error 1 Unexpected keyword 'abstract' in member definition. Expected 'member', 'override' or other token. D:\MinorApps\VetCompass\VetCompass\ViewModel\ViewModelBase.fs 18 7 VetCompass
Error 2 Incomplete structured construct at or before this point in pattern D:\MinorApps\VetCompass\VetCompass\ViewModel\ViewModelBase.fs 19 7 VetCompass
I'm not even sure where to begin with the indexer!
Upvotes: 3
Views: 2253
Reputation: 47904
Object expressions can often be used in lieu of abstract classes and virtual methods. You can control behavior through arguments supplied to a "factory" function. Something like this:
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] }
This probably won't work in your case, since you're constrained by the conventions of an existing framework. But it can be a nice alternative in some situations.
Upvotes: 5
Reputation: 12258
To implement IDataErrorInfo and INotifyPropertyChanged with a virtual implementation here is the code:
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)
Upvotes: 0
Reputation: 55184
All interface implementations are explicit, which means that the methods of the interface will be private when viewed as members of the class. Thus, you can't use the abstract
and default
modifiers in the implementation. Instead, you'll need to add a bit of duplication:
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
Upvotes: 9