2012-02-08 8 views
6

Quindi, quando mai sto creando alcune proprietà nel mio codice F #, dato che F # non supporta le proprietà auto, per quanto ne so. Devo creare campi di supporto e inizializzarli su null, il che non sembra corretto in termini di programmazione funzionale. Ad es.F # properties design

 

let mutable albums : DbSet = null 
let mutable genres : DbSet = null

member x.Albums with get() = albums and set(value) = albums <- value member x.Genres with get() = genres and set (value) = genres <- value

c'è un modo migliore di fare questo?. Mille grazie per i tuoi suggerimenti.

+1

Una cosa - oltre a Pad ed eccellenti risposte di TomasPetricek: se si sta veramente cercando di essere "funzionale" quindi vorrei esaminare il presupposto che avete bisogno di classi o classe- come strutture in primo luogo. Le proprietà automatiche violano la buona conoscenza delle informazioni esponendo le parti interne di una determinata classe al resto dell'app. Se ti serve l'interno di una classe esposta al resto dell'app, allora forse non hai bisogno della classe in primo luogo. Suppongo che stia dicendo che se vuoi davvero pensare a una cosa funzionalmente, togliti l'idea che tutto debba essere in una classe. –

+0

Oh e un'altra cosa: visto ciò su cui stai lavorando, potresti trovare utile questo post sul blog: http://bugsquash.blogspot.com/2011/11/lenses-in-f.html –

risposta

10

F # non supporta le proprietà di auto quando si ha bisogno di un mutevole proprietà , ma supporta una sintassi leggero quando si ha bisogno solo di una proprietà di sola lettura . Se si scrive un po 'di codice funzionale, quindi utilizzando sola lettura proprietà potrebbe in realtà essere più appropriato:

type Music(genres : DbSet, albums : DbSet) = 
    member x.Albums = albums 
    member x.Genres = genres 

Questo è essenzialmente lo stesso di record suggerite dal pad, ma può essere più appropriato se si desidera avere controllo migliore su come appaiono i tipi (e come appaiono in C# o per l'associazione dati).

Se DbSet è un tipo mutabile, è possibile utilizzare il tipo precedente e inizializzarlo solo una volta (sarà comunque possibile modificare i valori DbSet). Se si desidera modificare il valore DbSet, è possibile aggiungere un metodo che restituisce un oggetto clonato:

member x.WithAlbums(newAlbums) = 
    Music(genres, newAlbums) 

Utilizzando null o Unchecked.defaultOf<_> in F # è considerato una pessima pratica e si dovrebbe sempre cercare di creare l'oggetto completamente initlized. Se il valore è mancante, è possibile utilizzare il tipo option per rappresentarlo, ma in tal caso è necessario scrivere sempre il gestore per il valore mancante, per rendere sicuro il proprio programma.

+0

che esattamente quello che pensavo di usare null non può essere considerato una buona pratica in un linguaggio che ha tipi di Opzione espliciti proprio per questo scopo. Grazie per i vostri suggerimenti. – netmatrix01

+0

WPF accetta tipi di opzioni a favore di null espliciti? – Maslow

5

A meno che non si stia facendo qualcosa di complesso, consiglierei di utilizzare i record anziché le classi. In sostanza, essi sono classi con caratteristiche extra: immutabilità, l'uguaglianza strutturale, pattern matching, ecc:

type Playlists = { 
    Albums: DbSet; 
    Genres: DbSet 
    } 

È possibile ottenere i campi di registrare facilmente:

let p = {Albums = ...; Genres = ...} 
let albums = p.Albums 
let genres = p.Genres 

Nei campi di record predefiniti sono immutabili; puoi dichiarare campi mutabili nei record, ma è considerato una cattiva pratica. Sebbene non sia possibile impostare le proprietà, è possibile creare un nuovo record da uno vecchio. immutabilità di default non è normalmente un problema, inoltre, rende il codice più funzionale e più facile ragionare su:

let p = {Albums = a; Genres = g} 

    // Create new records by updating one field 
    let p1 = {p with Albums = a1} 
    let p2 = {p with Genres = g2} 

Se si insiste a creare classi, utilizzando un costruttore con parametri espliciti è consigliato:

type Playlists(a: DbSet, g: DbSet) = 
    let mutable albums = a 
    let mutable genres = g 
    // ... 

Quando un costruttore di default è necessario, è possibile utilizzare Unchecked.default<'T> per i campi non annullabili, o meglio usare i loro costruttori predefiniti:

// Set fields using dump values 
let mutable albums = new DbSet() 
let mutable genres = new DbSet() 

Ma assicurati di aver impostato quei campi prima di usarli effettivamente.

+0

Nota che puoi anche rendere i campi di un record mutabili nel modo più semplice. I record hanno anche alcuni svantaggi, ad esempio, devi impostare in modo esplicito il valore di tutti i suoi campi per costruire un oggetto. Un altro svantaggio è che i tipi di record non possono ereditare e non possono essere derivati ​​da. – ShdNx

+1

È vero che i record possono avere campi mutabili. Ma lo considero un cattivo design. Quando vai in quel modo, le lezioni dovrebbero essere preferite. – pad

+0

Grazie Pad per i vostri suggerimenti. Forse userò i record ma nel mio caso penso che sia più interessato a una proprietà. Ma ripenserò al tuo suggerimento e vedrò se riesco a progettare il mio tipo come Record. – netmatrix01

5

FYI - le proprietà automatiche sono pianificate per F # 3.0. Vedi lo preview documentation [MSDN].Sembra che il tuo esempio sarebbe diventato:

type Music() = 
    member val Albums : DbSet = null with get, set 
    member val Genres : DbSet = null with get, set 
+0

apparentemente queste cose non possono essere private – Maslow

+0

'membro val GroupBox1: GroupBox = new GroupBox()' lancia dicendo 'Informazioni aggiuntive: L'inizializzazione di un oggetto o valore ha comportato l'accesso di un oggetto o valore in modo ricorsivo prima che fosse completamente inizializzato. Questo costruttore sembra funzionare dopo la classe che tiene il costruttore della proprietà automatica. – Maslow

+0

Certo che sono: 'membro val privato ...' – Daniel