2014-04-27 2 views
7

Sto giocando un po 'con le interfacce F #, creando una semplice classe di accesso ai dati.Esiste un modo più semplice per utilizzare implicitamente le interfacce in F #?

L'interfaccia è:

type IUserAccess = 
    abstract member GetUsers : (dbSchema.ServiceTypes.Users -> bool) -> dbSchema.ServiceTypes.Users seq 
    abstract member GetAllUsers : unit -> dbSchema.ServiceTypes.Users seq 

Nella classe, sto chiamando i metodi in questo modo:

type UserAccess() = 
    let db = dbSchema.GetDataContext() 
    interface IUserAccess with 
     member this.GetUsers cond = 
      let query = query { 
       for row in db.Users do 
       select row } 
      query |> Seq.where cond 

     member this.GetAllUsers() = 
      (this:>IUserAccess).GetUsers (fun _ -> true) 

Quello che mi sono un po 'preoccupato è il modo in cui sto chiamando GetAllUsers funzione, in particolare con la parte (this:>IUserAccess). Qual è il modo più semplice per chiamare metodi implementati all'interno della stessa interfaccia?

Una semplice opzione mi viene in mente è la creazione di GetUsers metodo direttamente all'interno UserAccess() classe e quindi chiamando dal implementazione dell'interfaccia di entrambi GetUsers e GetAllUsers, ma che significa un nuovo metodo privato implementato, che vorrei evitare. C'è un'altra opzione?

risposta

6

F # implementa sempre le interfacce in modo esplicito, in modo che le opzioni sono più o meno come lei ha affermato, ma si può evitare di colata ridondante con l'introduzione di un let vincolante:

type IUserAccess = 
    interface 
     abstract member GetUsers : (obj -> bool) -> unit 
     abstract member GetAllUsers : unit -> unit 
    end 

type Foo() as self = 
    let userAccess = self :> IUserAccess 
    interface IUserAccess with 
     member this.GetUsers(q : (obj -> bool)) : unit = 
      () 
     member this.GetAllUsers() = 
      userAccess.GetUsers(fun _ -> true) 

Ho appena semplificato l'interfaccia e oggetto così ho potuto ottenere qualcosa che compila in modo veloce.

+0

Grazie, questo è esattamente il miglioramento semplice che stavo cercando! –

7

Penso che la soluzione di @vcsjones sia probabilmente l'opzione migliore se si desidera evitare di definire un metodo separato direttamente all'interno della classe. Detto questo, dichiarare un metodo separato in realtà non è così brutto. È possibile utilizzare la definizione locale utilizzando let vincolante (che è compilato automaticamente come un metodo privato) e penso che rende il codice sembrano abbastanza bello:

type UserAccess() = 
    let db = dbSchema.GetDataContext() 
    let getUsers cond = 
     let query = query { 
      for row in db.Users do 
      select row } 
     query |> Seq.where cond 

    interface IUserAccess with 
     member this.GetUsers cond = getUsers cond 
     member this.GetAllUsers() = getUsers (fun _ -> true) 

Io generalmente piace molto questo stile, perché separa tutto l'implementazione privata dalla parte della definizione in cui stai definendo l'API pubblica esposta.