2016-06-04 18 views
5

Sto provando a creare una piccola porzione di codice in F #. L'idea è che avrei un'interfaccia che definisce alcuni metodi, proprietà ed eventi. Usando questa interfaccia voglio definire una classe astratta (con un tipo generico) che implementerebbe alcune proprietà/metodi ma non tutti i membri definiti nell'interfaccia. La responsabilità di definire tutti i membri sarebbe nelle classi derivate.Interfacce e classi astratte in F #

Finora sono bloccato con l'interfaccia e la classe astratta. I problemi che sto avendo:

  • La definizione della classe astratta non riconosce la definizione di interfaccia
  • Non sono sicuro di come definire i membri astratti per l'interfaccia nella classe astratta

L'interfaccia si compila bene ma la classe astratta ha diversi errori. I messaggi sono inclusi nel codice

Tutti i commenti, le correzioni, i suggerimenti, ecc. Sono apprezzati. Poiché questa è la mia prima prova su F # ci sono probabilmente molti errori da segnalare.

Il codice che ho finora

definizione dell'interfaccia

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 

E la classe astratta

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

risposta

7

La definizione della classe astratta non riconosce la definizione di interfaccia

L'interfaccia deve essere declared above la classe astratta: in un progetto/assieme di riferimento, in un file sopra il file corrente (l'ordine dei file è importante) o superiore nello stesso file.

Non sono sicuro di come definire i membri astratti per l'interfaccia nella classe astratta

Purtroppo dobbiamo implementare tutti i membri dell'interfaccia, per mantenere il comportamento desiderato si può avere la chiamata implementazione membro astratta della classe che ha la stessa firma:

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

la proprietà Y è definito due volte che sembra un po 'strano in un primo momento. L'implementazione dell'interfaccia rimanda all'implementazione sulla classe - questo significa che per accedere a Y non sarà necessario aggiornare un'istanza della classe all'interfaccia, l'ho fatto per mantenere lo stesso comportamento del tuo esempio iniziale

al tuo commento:

per ottenere un membro virtuale su una classe astratta è necessario dichiarare il membro come astratto e di fornire un'implementazione di default, ecco un esempio per abbinare il codice nel tuo commento:

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 

Generalmente OO F # è usato per interagire con il resto del.Mondo NET: sembra il caso qui. Ma se il codice non interagisce con un'altra API .NET che richiede un'interfaccia OO, è possibile che la modellazione del problema con un approccio funzionale possa comportare un codice più pulito. OO in F # potrebbe non dare una buona impressione iniziale della lingua (anche se personalmente mi piace abbastanza l'esplicita e la brevità di esso)

+0

Grazie per l'aiuto. Sono ancora solo bloccato dall'ereditarietà e dall'override dei metodi. La classe astratta ora definisce 'member this.NewTrendItem() = null' e la classe derivata assomiglia a' type NumberItem() = inherit ValueItem () ...... override this.NewTrendItem() = new NumberItem () '. Tuttavia, sto ricevendo _Non è stato trovato alcun elemento astratto o interfaccia corrispondente a questo errore di override_. – user6423491

+0

Nessun problema, spero che stia aiutando. Ho aggiornato il commento per fornire un esempio di come potresti farlo. –

Problemi correlati