2013-08-30 14 views
14

F # rende facile definire i tipi, comeCome fare la convalida degli argomenti di F # record

type coords = { X : float; Y : float } 

ma come faccio a definire i vincoli/check argomenti per il costruttore senza entrare nel sintassi più prolissa definizione di classe? Per esempio. se voglio che i coords inizino da (0,0) o generino un'eccezione.

Inoltre, se cambio la mia definizione in una classe ho bisogno di implementare Equals() ecc. Tutto il codice della piastra della caldaia che non voglio (e che ho in C# che sto cercando di scappare) .

+1

possibile duplicato di [È possibile imporre che un record rispetti alcuni invarianti?] (Http://stackoverflow.com/questions/13925361/is-it-possibile-per-esporre-che-a-record-respects -some-invarianti) –

+0

Questo è un duplicato dell'altra domanda. Vota per chiudere. –

risposta

13

Si può fare l'attuazione privata. Ottieni uguaglianza strutturale, ma perdi l'accesso diretto al campo e la corrispondenza dei modelli. È possibile ripristinare quell'abilità usando schemi attivi.

//file1.fs 

type Coords = 
    private { 
    X: float 
    Y: float 
    } 

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] 
module Coords = 
    ///The ONLY way to create Coords 
    let create x y = 
    check x 
    check y 
    {X=x; Y=y} 

    let (|Coords|) {X=x; Y=y} = (x, y) 

//file2.fs 

open Coords 
let coords = create 1.0 1.0 
let (Coords(x, y)) = coords 
printfn "%f, %f" x y 
+2

Questa è una buona soluzione Daniel. Vorrei che lo inventassi. –

+3

Grazie, la mia sensazione istintiva mi dice che questo è un approccio molto complicato e non molto tipico nel fare tipi? Immagino che fare una lezione e implementare Equals sia preferibile .. o far rispettare tutti i tipi del mio programma che sono costruiti attraverso un metodo di creazione generico? –

+0

È raro, sì, ma solo contorto come lo si fa. Penso che l'implementazione privata sia una buona funzionalità e utile per alcuni scenari non comuni. – Daniel

4

è necessario utilizzare la sintassi definizione di classe:

type coords(x: float, y: float) = 
    do 
    if x < 0.0 then 
     invalidArg "x" "Cannot be negative" 
    if y < 0.0 then 
     invalidArg "y" "Cannot be negative" 

    member this.X = 
    x 
    member this.Y = 
    y 
+2

se cambio la mia definizione in una classe ho bisogno di implementare Equals() ecc. Tutto il codice della piastra della caldaia che non voglio (e che ho in C# che sto cercando di scappare). –

+0

Sì, devi farlo. Se si desidera l'incapsulamento/occultamento dei dati orientato agli oggetti, è necessario disporre di elementi simili a C# orientati agli oggetti, senza dubbio. La cosa bella di F # è che puoi farlo. – MiMo

+4

quindi quale sarebbe il modo F #? definire una classe o definire una funzione di creazione nello stesso modulo del record e sperare che la gente usi il metodo di creazione? –

5

C'è una serie chiamata Designing with Types su F# for fun and profit. Nella sezione "Forzare l'uso del costruttore" si raccomanda l'uso delle funzioni di costruzione - è qui che le convalide vanno prima che il tipo venga istanziato. Per impedire alle persone di creare istanze di tipo diretto, consiglia le convenzioni di denominazione oi file di firma.

È possibile trovare molti altri articoli ed esempi pertinenti tramite googling "domain driven design f #".

Nota che vengo da C#/Non ho applicato F # al nostro livello dominio (ancora;) Non riesco davvero a capire come uno dei metodi consigliati possa funzionare in un progetto più grande. Alcune cose sembrano ... diverse in questo nuovo mondo coraggioso.

Problemi correlati