2010-10-27 60 views
11

我知道如何使用可变对象在F#中进行序列化,但是有没有办法使用XmlSerializer或DataContractSerializer使用记录类型来序列化/反序列化?貌似有一种方法可以使用KnownType属性识别联合做到这一点,但是我正在寻找一种方式来使用非可变记录没有默认构造函数...记录类型的F#序列化

+0

我结束了刚刚使用XML解析,这在我的情况,以及我试图没有工作产生干净的XML,即使托马斯的建议使用System.Xml.Serialization的属性,我的怀疑是它是不会工作,但我决定尝试反正他们没有,我相信因为datacontract的命名空间忽略了这些。我的要求是在这个练习中使用非可变记录,但是如果你的目标只是xml序列化,那么它就和以任何其他.net语言使用它没什么两样,只需创建类,装饰它们并使用XmlSerializer,它就可以工作。 – Alex 2010-11-29 16:27:29

回答

9

样品code for reading data from Freebase由乔莫·费希尔使用DataContractJsonSerializer到将数据加载到不可变的F#记录中。记录的声明,他使用这个样子的:

[<DataContract>] 
type Result<'TResult> = { // ' 
    [<field: DataMember(Name="code") >] 
    Code:string 
    [<field: DataMember(Name="result") >] 
    Result:'TResult // ' 
    [<field: DataMember(Name="message") >] 
    Message:string } 

这里的关键点是,在DataMember属性附加到这实际上是用来存储数据,而不是只读属性的基础字段F#编译器生成(使用属性上的field:修饰符)。

我不是100%肯定这是否会与其他类型的序列化(可能不是)工作,但它可能是一个有用的指针开始...

编辑我不知道如果我失去了一些东西,但以下基本示例工作正常,我:

module Demo 

#r "System.Runtime.Serialization.dll" 

open System.IO 
open System.Text 
open System.Xml 
open System.Runtime.Serialization 

type Test = 
    { Result : string[] 
    Title : string } 

do 
    let sb = new StringBuilder() 
    let value = { Result = [| "Hello"; "World" |]; Title = "Hacking" } 
    let xmlSerializer = DataContractSerializer(typeof<Test>); 
    xmlSerializer.WriteObject(new XmlTextWriter(new StringWriter(sb)), value) 
    let sr = sb.ToString() 
    printfn "%A" sr 

    let xmlSerializer = DataContractSerializer(typeof<Test>); 
    let reader = new XmlTextReader(new StringReader(sr)) 
    let obj = xmlSerializer.ReadObject(reader) :?> Test 
    printfn "Reading: %A" obj 

EDIT 2如果你想生成XML更清洁,那么你可以添加的属性是这样的:

[<XmlRoot("test")>] 
type Test = 
    { [<XmlArrayAttribute("results")>] 
    [<XmlArrayItem(typeof<string>, ElementName = "string")>] 
    Result : string[] 
    [<XmlArrayAttribute("title")>] 
    Title : string } 
+0

这是一个开始,但生成的xml不是“干净的”,我的意思是标签就像“FSI_0132”。测试“,而不是测试和Title_x0040_而不是标题。我也看起来像不能使用[]属性的类型设置xml标记。换句话说,xml看起来中间,而不是我真的可以使用.btw,Tomas,我开始阅读你的真实世界功能编程书,它看起来非常好迄今。 – Alex 2010-10-27 17:02:19

+0

命名空间“FSI_0132”由F#Interactive生成 - 在编译后的代码中,它将替换为实际的命名空间。不知道的属性名称,但 – 2010-10-27 17:12:53

+0

@Joel:对,我明白,但我的目标是有干净的XML没有任何名称空间的信息,就像您如果你试图在.NET – Alex 2010-10-27 17:24:32

1

您可以使用这一系列的注解上的类的属性设置格式的XML:

[XmlRoot("root")] 
[XmlElement("some-element")] 
[XmlAttribute("some-attribute")] 
[XmlArrayAttribute("collections")] 
[XmlArrayItem(typeof(SomeClass), ElementName = "item")] 

我使用的属性在我的C#类,但在F#反序列化(C#类INA引用LIB)。

在F#

use file = new FileStream(filePath, FileMode.Open) 
let serializer= XmlSerializer(typeof<SomeClass>) 
let docs = serializer.Deserialize file :?> SomeClass 
+1

这很酷,但要求是使用非可变类型,所以这方法将无法正常工作,因为该类将有可变字段 – Alex 2010-10-27 20:21:33

9

它不使用的XmlSerializer或DataContractSerializer的,但Json.NET 6.0 includes nice F# support.

它看起来像这样:

type TestTarget = 
    { a: string 
     b: int } 

[<TestFixture>] 
type JsonTests() = 
    [<Test>] 
    member x.``can serialize``() = 
     let objectUnderTest = { TestTarget.a = "isa"; b = 9 } 
     let jsonResult: string = Newtonsoft.Json.JsonConvert.SerializeObject(objectUnderTest) 
     printfn "json is:\n%s" jsonResult 
     let xmlResult = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonResult, "root") 
     printfn "xml is:\n%s" (xmlResult.OuterXml) 

     let jsonRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(jsonResult) 
     printfn "json roundtrip: %A" jsonRoundtrip 

     let xmlAsJson = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlResult, Newtonsoft.Json.Formatting.Indented, true) 
     printfn "object -> json -> xml -> json:\n%A" xmlAsJson 
     let xmlRoundtrip = Newtonsoft.Json.JsonConvert.DeserializeObject<TestTarget>(xmlAsJson) 
     printfn "xml roundtrip:\n%A" xmlRoundtrip 

     Assert.That(true, Is.False) 
     () 

json is: 
{"a":"isa","b":9} 
xml is: 
<root><a>isa</a><b>9</b></root> 
json roundtrip: {a = "isa"; 
b = 9;} 
object -> json -> xml -> json: 
"{ 
    "a": "isa", 
    "b": "9" 
}" 
xml roundtrip: 
{a = "isa"; 
b = 9;} 
+0

真棒,用于显示使用记录类型的方式,而不需要'[]'attr(只需升级newto nsoft) – Maslow 2015-02-01 16:46:41

+0

我发现这并不尊重成员名称的大小写敏感性(它们总是转换为小写)。 – 2015-10-05 17:17:57