我知道如何使用可变对象在F#中进行序列化,但是有没有办法使用XmlSerializer或DataContractSerializer使用记录类型来序列化/反序列化?貌似有一种方法可以使用KnownType属性识别联合做到这一点,但是我正在寻找一种方式来使用非可变记录没有默认构造函数...记录类型的F#序列化
回答
样品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 }
这是一个开始,但生成的xml不是“干净的”,我的意思是标签就像“FSI_0132”。测试“,而不是测试和Title_x0040_而不是标题。我也看起来像不能使用[
命名空间“FSI_0132”由F#Interactive生成 - 在编译后的代码中,它将替换为实际的命名空间。不知道的属性名称,但 – 2010-10-27 17:12:53
@Joel:对,我明白,但我的目标是有干净的XML没有任何名称空间的信息,就像您如果你试图在.NET – Alex 2010-10-27 17:24:32
您可以使用这一系列的注解上的类的属性设置格式的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
这很酷,但要求是使用非可变类型,所以这方法将无法正常工作,因为该类将有可变字段 – Alex 2010-10-27 20:21:33
它不使用的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;}
真棒,用于显示使用记录类型的方式,而不需要'[
我发现这并不尊重成员名称的大小写敏感性(它们总是转换为小写)。 – 2015-10-05 17:17:57
与F#3.0开始,记录的系列化现在通过将CliMutableAttribute
应用于该类型支持类型。例如:
[<CLIMutable>]
type MyRecord = { Name : string; Age : int }
此示例来自http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx,其包括该功能的讨论中和在其他三个新的功能采取F#3.0:三重引用的字符串,自动属性,和未使用的变量的警告。
- 1. 序列化f#代数数据类型
- 2. printf类型的日志记录F#
- 3. F#泛型记录
- 4. 可变F#记录的二进制序列化
- 5. 简化F#记录分配
- 6. 从参数化记录类型实例化Clojurescript中的记录?
- 7. “序列化” VHDL记录
- 8. F#界面/抽象类型和序列化
- 9. 序列化数据类型以通过F#网络使用
- 10. MonoTouch:如何序列化未标记为可序列化的类型(如CLLocation)?
- 11. F#对尚未分配值的记录排序序列
- 12. F#:一个复杂的记录类型和一个DataGridView
- 13. F#多维阵列类型
- 14. 简化记录类型Id链接
- 15. 反序列化与F#
- 16. 记录列表的TypeScript数据类型
- 17. OCaml序列化与类型
- 18. 序列化类型定义?
- 19. 序列化返回类型
- 20. 反序列化泛型(但可序列化)类型
- 21. F#类型推断与记录奇行为
- 22. 在运行时从C#中检测F#记录类型
- 23. 继承F#记录
- 24. F#sqlProvider的SQLite的忽略列类型
- 25. 将相关记录序列化为json导轨模型
- 26. 筛选记录时,列类型为varchar
- 27. 动态列名记录类型可变
- 28. 如何在J#中序列化F#中的数学向量类型?
- 29. 序列化为XML并包含序列化对象的类型
- 30. 记录对象状态序列化
我结束了刚刚使用XML解析,这在我的情况,以及我试图没有工作产生干净的XML,即使托马斯的建议使用System.Xml.Serialization的属性,我的怀疑是它是不会工作,但我决定尝试反正他们没有,我相信因为datacontract的命名空间忽略了这些。我的要求是在这个练习中使用非可变记录,但是如果你的目标只是xml序列化,那么它就和以任何其他.net语言使用它没什么两样,只需创建类,装饰它们并使用XmlSerializer,它就可以工作。 – Alex 2010-11-29 16:27:29