Ale*_*lex 13 serialization f# xml-serialization
我知道如何使用可变对象在F#中序列化,但有没有办法使用XmlSerializer或DataContractSerializer使用记录类型序列化/反序列化?看起来有一种方法可以使用KnownType属性为一个有区别的联合做到这一点,但我正在寻找一种方法来使用没有默认构造函数的非可变记录...
Tom*_*cek 13
Jomo Fisher 从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 }
Run Code Online (Sandbox Code Playgroud)
这里的关键点是该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
Run Code Online (Sandbox Code Playgroud)
编辑2如果您想生成更干净的XML,那么您可以添加如下属性:
[<XmlRoot("test")>]
type Test =
{ [<XmlArrayAttribute("results")>]
[<XmlArrayItem(typeof<string>, ElementName = "string")>]
Result : string[]
[<XmlArrayAttribute("title")>]
Title : string }
Run Code Online (Sandbox Code Playgroud)
pho*_*oog 13
从F#3.0开始,现在通过应用类型来支持记录类型的序列化CliMutableAttribute.例:
[<CLIMutable>]
type MyRecord = { Name : string; Age : int }
Run Code Online (Sandbox Code Playgroud)
此示例来自http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx,其中包括对此功能的讨论和三个F#3.0中的其他新功能:三引号字符串,自动属性和未使用的变量警告.
它不使用XmlSerializer或DataContractSerializer,但Json.NET 6.0包含很好的F#支持.
它看起来像这样:
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;}
Run Code Online (Sandbox Code Playgroud)