Getting the types in an F# union type
This arose in the context of performing data contract serialization of a union type, and needing to feed the concrete types in as known types. As the FSharp.Reflection facilities only let you at the names of the union cases, it's necessary to rely on the secret knowledge that the union cases are implemented as nested subtypes of the abstract union type
open System | |
open Microsoft.FSharp.Reflection | |
let GetUnionTypes (t:Type) = | |
seq { yield t | |
if FSharpType.IsUnion t | |
then yield! FSharpType.GetUnionCases t | |
// implementation detail leaks here -- nested type name | |
|> Seq.map (fun x -> (string t) + "+" + x.Name) | |
|> Seq.map Type.GetType } | |
type expr = Num of int | |
| Operation of (expr * expr) | |
let baseType = typeof<expr> | |
GetUnionTypes baseType | |
|> Seq.iter (printfn "%A") | |
;; | |
Then we can serialize objects of the union type like
open System.IO | |
open System.Runtime.Serialization.Json | |
open System.Text | |
let exprTypes = GetUnionTypes baseType | |
let ToJson<'t> (myObj:'t) = | |
use ms = new MemoryStream() | |
DataContractJsonSerializer(typeof<'t>, exprTypes).WriteObject(ms, myObj) | |
Encoding.Default.GetString(ms.ToArray()) | |
let FromJson<'t> (jsonString:string) : 't = | |
use ms = new MemoryStream(Encoding.Default.GetBytes(jsonString)) | |
let obj = DataContractJsonSerializer(typeof<'t>, exprTypes).ReadObject(ms) | |
obj :?> 't | |
let value = Num 3 | |
let json = ToJson value | |
let recovered : expr = FromJson json | |
;; | |
val exprTypes : seq<Type> | |
val ToJson : myObj:'t -> string | |
val FromJson : jsonString:string -> 't | |
val value : expr = Num 3 | |
val json : string = "{"__type":"FSI_0002.expr.Num:#","item":3}" | |
val recovered : expr = Num 3 |
where we feed the list of types to be known to the constructor for the serializer.
No comments :
Post a Comment