2015-08-05 8 views
7

Sto provando a prendere confidenza con F # e nel processo sto convertendo un codice C#. Ho qualche problema con la definizione delle proprietà in un'interfaccia e l'implementazione in un tipo.Interfacce e proprietà F #

Si consideri il seguente codice:

module File1 

type IMyInterface = 
    abstract member MyProp : bool with get, set 
    abstract member MyMethod : unit -> unit 

type MyType() = 
    interface IMyInterface with 
     member val MyProp = true with get, set 
     member self.MyMethod() = if MyProp then() else() 

The documentation for F# properties sembra affermare che la mia realizzazione di MyProp in MyType è corretto, tuttavia, il compilatore si lamenta che "il valore o il costruttore 'MyProp' non è definita". Qualche idea?

+2

prova 'self.MyProp' - è necessario il' this' qualificazione;) – Carsten

+0

@Carsten che non sembra funzionare con proprietà auto – Eyvind

+0

vedere la mia risposta qui sotto – Carsten

risposta

13

per accedere alla proprietà all'interno di un'interfaccia (esplicito) è necessario per lanciare al riferimento self per il tipo di interfaccia:

type MyType() = 
    interface IMyInterface with 
     member val MyProp = true with get, set 
     member self.MyMethod() = if (self :> IMyInterface).MyProp then() else() 

si ottiene lo stesso errore in C#, se si implementa l'interfaccia in modo esplicito, e un cast è necessaria anche per accedere al membro:

interface IMyInterface 
{ 
    bool MyProp { get; set; } 
    void MyMethod(); 
} 

class MyType : IMyInterface 
{ 
    bool IMyInterface.MyProp { get; set; } 

    void IMyInterface.MyMethod() 
    { 
     if (((IMyInterface)this).MyProp) { } 
    } 
} 
+0

Aha! Non ero a conoscenza del fatto che si trattava in realtà di un'implementazione esplicita dell'interfaccia. C'è un modo per implementarlo implicitamente? – Eyvind

+3

Per quanto ne so in F # tutte le interfacce devono essere esplicitamente implementate. Scott lo spiega bene qui http://fsharpforfunandprofit.com/posts/interfaces/ – Kevin

+1

Nessun problema, e sì nelle interfacce F # può essere implementato solo esplicitamente –

4

Ecco una versione di lavoro:

type IMyInterface = 
    abstract member MyProp : bool with get, set 
    abstract member MyMethod : unit -> unit 

type MyType() = 
    member val MyProp = true with get, set 
    member self.MyMethod() = if self.MyProp then() else() 
    interface IMyInterface with 
     member self.MyProp with get() = self.MyProp and set v = self.MyProp <- v 
     member self.MyMethod() = self.MyMethod() 

si prega di notare che ho incluso i membri espliciti come sicuramente avrebbe perso loro;)

+0

So che questo funziona, ma voglio proprietà auto, non campi di backing espliciti ... – Eyvind

+1

'MyProp' è una proprietà auto - è solo l'implementazione dell'interfaccia che sovrascrive questo - forse c'è un modo più breve ma sinceramente cerco di non usare valori mutabili comunque non lo so per certo;) – Carsten

+0

Sì, so che usare le proprietà mutabili non è esattamente F #, ma nel mio vero scenario, l'interfaccia che sto implementando è definita in C#, e non qualcosa che posso cambiare. Tuttavia, la tua soluzione sembra più un casino (senza offesa intesa) di quanto dovrebbe essere; si spera che qualcuno inserisca un codice più succinto :) – Eyvind

6

Se sei solo l'accesso all'interfaccia, allora non c'è bisogno di definire i membri del tipo stesso. La risposta di Phil è buona se vuoi il minimalismo, ma un altro approccio Mi piace usare i valori "let-bound" piuttosto che i membri - per codice più complesso, l'inferenza di tipo è migliore e sono generalmente più facili da gestire rispetto ai membri .

type MyType() = 
    let mutable myProp = true 
    let myMethod() = if myProp then() else() 

    interface IMyInterface with 
     member __.MyProp with get() = myProp and set v = myProp <- v 
     member __.MyMethod() = myMethod() 

il codice è un po 'più pulito rispetto alle versioni membri così, imo, perché il tag self in type MyType() as self è necessaria solo per accedere membri - Valori let-bound è accessibile direttamente dall'interfaccia.

+0

Questo è bello; Grazie! – Eyvind

+1

Il modo in cui mi piace pensarlo è: (a) faccio tutto il lavoro reale con valori e funzioni rilegati (equivalenti ai metodi privati, diciamo) e poi (b) espongo alcune di queste funzionalità attraverso una o più interfacce . Le interfacce sono quindi semplicemente proxy al codice "reale". – Grundoon