2010-09-15 57 views
2

我需要將使用F#區分的聯合表示的抽象語法樹保留爲人類可讀的緊湊格式,例如已經在F#語言中使用的格式來構造區分的聯合體,以便以後可以讀回歧視聯合實例。我對F#庫不支持這一點感到有點驚訝,因爲它肯定必須以編譯器和F#交互式的高效方式完成。我在哪裏可以找到F#歧視工會的序列化程序?

是否有任何免費/開放源代碼實現在合理的(但不一定非常有效)的方式做到這一點?

注意:我不想要基於XML的序列化。

回答

5

編輯:下面的答案都不符合您的標準,但我張貼的情況下其他人尋找聯盟序列化發現他們有用。我不知道任何庫的方式,以重新解析聯合的sprintf "%A"輸出 - 請記住,編譯器和FSI有一個很不同的任務,知道範圍和處理名稱空間和限定的名稱和陰影和什麼,甚至忽略這一點,解析工會(數據,字符串,任意對象等)攜帶的數據本身可能是一項完整的任務。

下面是聯盟序列化的一種策略,作爲一個小樣本程序的一部分。 (KnownTypeAttribute可以採用方法名稱,並且可以使用一些反射來獲取類型。)這是向聯合添加一小段代碼以獲得序列化的一種非常簡單的方法。

open Microsoft.FSharp.Reflection 
open System.Reflection 
open System.Runtime.Serialization 
open System.Xml 

[<KnownType("KnownTypes")>] 
type Union21WithKnownTypes = 
    | Case1 of int * int 
    | Case2 of string 
    static member KnownTypes() = 
     typeof<Union21WithKnownTypes>.GetNestedTypes(
      BindingFlags.Public 
      ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion 

let dcs = new DataContractSerializer(typeof<Union21WithKnownTypes[]>) 
let arr = [| Case1(1,1); Case2("2") |] 
printfn "orig data: %A" arr 
let sb = new System.Text.StringBuilder() 
let xw = XmlWriter.Create(sb) 
dcs.WriteObject(xw, arr) 
xw.Close() 
let s = sb.ToString() 
printfn "" 
printfn "encoded as: %s" s 
printfn "" 
let xr = XmlReader.Create(new System.IO.StringReader(s)) 
let o = dcs.ReadObject(xr) 
printfn "final data: %A" o 

這裏的JSON版本:

open Microsoft.FSharp.Reflection 
open System.Reflection 
open System.Runtime.Serialization 
open System.Runtime.Serialization.Json 
open System.Xml 

[<KnownType("KnownTypes")>] 
type Union21WithKnownTypes = 
    | Case1 of int * int 
    | Case2 of string 
    static member KnownTypes() = 
     typeof<Union21WithKnownTypes>.GetNestedTypes( 
      BindingFlags.Public 
      ||| BindingFlags.NonPublic) |> Array.filter FSharpType.IsUnion 

let dcs = new DataContractJsonSerializer(typeof<Union21WithKnownTypes[]>) 
let arr = [| Case1(1,1); Case2("2") |] 
printfn "orig data: %A" arr 
let stream = new System.IO.MemoryStream() 
dcs.WriteObject(stream, arr) 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore 
let bytes = Array.create (int stream.Length) 0uy 
stream.Read(bytes, 0, int stream.Length) |> ignore 
let s = System.Text.Encoding.ASCII.GetString(bytes) 
printfn "" 
printfn "encoded as: %s" s 
printfn "" 
stream.Seek(0L, System.IO.SeekOrigin.Begin) |> ignore 
let o = dcs.ReadObject(stream) 
printfn "final data: %A" o 
相關問題