2013-07-24 7 views
8

Un'unione discriminato in F # viene compilato in una classe astratta e le sue opzioni diventano classi concrete nidificate.F # è a conoscenza dei moduli compilati dai sindacati discriminati?

type DU = A | B 

DU è astratta, mentre DU.A e DU.B sono concrete.

Con ServiceStack, la serializzazione di tipi di stringhe e indietro JSON possono essere personalizzati con le funzioni. Per quanto riguarda il tipo di DU, ecco come ho potuto farlo in C#.

using ServiceStack.Text; 

JsConfig<DU.A>.SerializeFn = v => "A"; // Func<DU.A, String> 
JsConfig<DU.B>.SerializeFn = v => "B"; // Func<DU.B, String> 
JsConfig<DU>.DeserializeFn = s => 
    if s == "A" then DU.NewA() else DU.NewB(); // Func<String, DU> 

F # è a conoscenza delle forme compilate dai sindacati discriminati? Come potrei ottenere il tipo di DU.A in F # in fase di compilazione?

typeof<DU> // compiles 
typeof<DU.A> // error FS0039: The type 'A' is not defined 
typeof<A> // error FS0039: The type 'A' is not defined 

Posso facilmente registrare una funzione per la deserializzazione in F #.

open System 
open ServiceStack.Text 

JsConfig<DU>.RawDeserializeFn <- 
    Func<_, _>(fun s -> printfn "Hooked"; if s = "A" then A else B) 

E 'possibile registrarsi serializzare funzioni totalmente in F # per i tipi concreti DU.A e DU.B?

risposta

8

Mentre tutti i comportamenti (le classi astratte, ecc) non è solo un dettaglio implemenation, in realtà è definito dalle specifiche, queste cose non sono accessibili da F # - questa è una citazione dal spec

un tipo unione compilato U ha:

· un CLI struttura getter statico UC per ciascun caso nullo unione C. Questa proprietà ottiene un oggetto singleton che rappresenta ciascuna di tali caso.

· Un CLI nidificato tipo UC per ogni caso l'unione non nullo C. Questo tipo ha proprietà dell'istanza ITEM1, item2 .... per ogni campo del caso unione, o di una singola proprietà di istanza dell'oggetto se c'è solo un campo . Tuttavia, un tipo di unione compilato che ha un solo caso non fa hanno un tipo annidato. Invece, il tipo di unione stessa svolge il ruolo di il tipo di caso.

· Un metodo statico CLI U.NewC per ogni caso di unione non nullo C. Questo metodo crea un oggetto per quel caso.

· Una proprietà di istanza CLI U.IsC per ogni caso C. Questa proprietà restituisce true o false per il caso.

· Una proprietà di istanza CLI U.Tag per ogni caso C. Questa proprietà recupera o calcola un tag intero corrispondente al caso.

· Se U ha più di un caso, ha un tipo nidificato CLI U.Tags. L'U.Tags typecontains uno letterale intero per ciascun caso, in ordine partendo da zero crescente.

· Un tipo di unione compilato ha i metodi richiesti per implementare le sue interfacce generate automaticamente, oltre a qualsiasi proprietà o metodi definiti dall'utente .

Questi metodi e proprietà non possono essere utilizzati direttamente da F #. Tuttavia, questi tipi hanno List.Empty user-facing, List.Contro, Option.None e Option.Some proprietà e/o metodi.

È importante notare che "questi metodi e proprietà non possono essere utilizzati da F #".

+0

Mi chiedo se questo è parte di F # lingua Spec, fa questo make attuazione F # in JVM impossibile? Perché CLI è parte del linguaggio ora. –

+0

@WeiMa - Suppongo che un'eredità simile possa essere modellata sulla JVM. Ci sono state alcune discussioni su come far compilare il compilatore alla JVM sulla mailing list, ma non penso ci siano piani seri. –

+0

@WeiMa: si noti che il linguaggio F # supporta funzioni come i tipi di valore e le chiamate di coda che la JVM non può nemmeno esprimere. –

5

Il fatto che un DU in F # sia un singolo tipo è fondamentale per la sua utilità. Il # approccio F sarebbe quella di utilizzare il pattern matching:

JsConfig<DU>.SerializeFn <- function 
    | A -> "A" 
    | B -> "B" 

Questo dovrebbe lavoro perché dell'Unione casi non sono solo i tipi nidificati in C#, ma sottotipi così. Naturalmente se ServiceStack non considera serializzatori di tipo base, questo non funzionerà.

4

Daniel è corretto, è possibile farlo registrando le funzioni di serializzazione per il tipo di base DU. Ecco un esempio più completo

open System 
open ServiceStack.Text 

type DU = A | B 

let serialize = function 
    | A -> "A" 
    | B -> "B" 

let deserialize = function 
    | "A" -> A 
    | "B" -> B 
    | _ -> failwith "Can't deserialize" 

JsConfig<DU>.SerializeFn <- Func<_,_>(serialize) 
JsConfig<DU>.DeSerializeFn <- Func<_,_>(deserialize) 

let value = [| A; B |] 
let text = JsonSerializer.SerializeToString(value) 
let newValue = JsonSerializer.DeserializeFromString<DU[]>(text) 

Risultato:

val value : DU [] = [|A; B|] 
val text : string = "["A","B"]" 
val newValue : DU [] = [|A; B|] 
Problemi correlati