2012-02-08 8 views
6

Así que cuando alguna vez estoy creando algunas propiedades en mi código F #, como F # no admite propiedades automáticas, por lo que yo sé. Tengo que crear campos de respaldo e inicializarlos en nulo, lo que no parece correcto en términos de programación funcional. Por ej.F # diseño de propiedades

 

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

¿Hay una mejor manera de hacer esto?. Muchas gracias por sus sugerencias.

+1

Una cosa - además de cojín y excelentes respuestas de TomasPetricek: Si está realmente tratando de ser "funcional" entonces yo examinar el supuesto de que lo que necesita clases o de clase como estructuras en primer lugar. Las propiedades automáticas violan la ocultación de buena información al exponer el interior de una clase determinada al resto de la aplicación. Si necesitas el interior de una clase expuesta al resto de la aplicación, entonces tal vez no necesites la clase en primer lugar. Supongo que estoy diciendo que si realmente quieres pensar funcionalmente, deshacerte de la idea de que todo tiene que ser una clase. –

+0

Ah, y una cosa más, teniendo en cuenta lo que está trabajando, es posible que este blog sea útil: http://bugsquash.blogspot.com/2011/11/lenses-in-f.html –

Respuesta

10

F # no admite propiedades de auto cuando se necesita un mutable propiedad, pero soporta una sintaxis de peso ligero cuando se necesita sólo una propiedad de sólo lectura . Si va a escribir algo de código funcional, a continuación, utilizando sólo lectura propiedades en realidad podría ser más apropiado:

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

Ésta es esencialmente la misma que los registros sugeridos por la almohadilla, pero puede ser más apropiado si usted quiere tener mejor control sobre cómo se ven los tipos (y cómo aparecen en C#, o para el enlace de datos).

Si DbSet es un tipo mutable, entonces probablemente solo pueda usar el tipo anterior e inicializarlo solo una vez (aún podrá modificar los valores DbSet). Si desea cambiar el valor DbSet, se puede añadir un método que devuelve un objeto clonado:

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

Usando null o Unchecked.defaultOf<_> en F # se considera una muy mala práctica y siempre se debe tratar de crear el objeto totalmente initlized. Si es posible que falte el valor, puede usar el tipo option para representarlo, pero luego debe escribir siempre el controlador para el valor faltante, para que su programa sea seguro.

+0

que exactamente lo que pensé usando null no puede considerarse una buena práctica en un lenguaje que tiene tipos de opciones explícitos solo para este propósito. Gracias por tus sugerencias – netmatrix01

+0

¿WPF acepta tipos de opciones a favor de nulos explícitos? – Maslow

5

A menos que esté haciendo algo complejo, le recomendaría utilizar registros en lugar de clases. Básicamente, son clases con características adicionales: la inmutabilidad, la igualdad estructural, la coincidencia de patrones, etc:

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

Puede obtener campos de grabar fácilmente:

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

En los campos de registros por defecto son inmutables; puede declarar campos mutables en los registros, pero se considera una mala práctica. Aunque no puede establecer propiedades, puede crear un nuevo registro a partir de uno anterior. inmutabilidad por defecto no es normalmente un problema, además, hace que el código sea más funcional y más fácil de razonar acerca de:

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} 

Si insiste para crear clases, usando un constructor con parámetros explícitos se recomienda:

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

Cuando es necesario un constructor por defecto, se puede utilizar para Unchecked.default<'T> campos no anulables, o mejor uso de sus constructores por defecto:

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

Pero asegúrese de establecer esos campos antes de usarlos realmente.

+0

Tenga en cuenta que puede también hacen que los campos de un registro mutable de manera trivial. Los registros también tienen algunas desventajas, por ejemplo, debe establecer explícitamente el valor de todos sus campos para construir un objeto. Otra desventaja es que los tipos de registros no pueden heredarse ni derivarse de ellos. – ShdNx

+1

Es cierto que los registros pueden tener campos mutables. Pero lo considero un mal diseño. Cuando va por ese camino, las clases deben ser preferidas. – pad

+0

Gracias Pad por sus sugerencias. Tal vez usaré registros, pero en mi caso creo que estoy más interesado en una propiedad. Pero me replantearé su sugerencia y veré si puedo diseñar mi tipo como un Registro. – netmatrix01

5

FYI - las propiedades automáticas están planificadas para F # 3.0. Vea el preview documentation [MSDN].Parece que tu ejemplo se convertiría en:

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

aparentemente estas cosas no pueden ser privadas – Maslow

+0

'member val GroupBox1: GroupBox = new GroupBox()' throws diciendo 'Información adicional: La inicialización de un objeto o valor dio como resultado un objeto o valor accedido recursivamente antes de que estuviera completamente inicializado. Este constructor parece ejecutarse después de la clase que contiene el constructor de propiedad automática. – Maslow

+0

Claro que son: 'miembro val privado ...' – Daniel

Cuestiones relacionadas