F# 将构造函数添加到记录中?
基本上我想要一个单一的构造来处理 JSON 和格式化 xml 的序列化。 Records 非常适合序列化到 json 或从 json 序列化。但是,XmlSerializer 需要无参数构造函数。我真的不想经历为这些构造构建类对象的练习(仅原理)。我希望可以有一些快捷方式将无参数构造函数添加到记录上(也许使用 wioth 语句或其他东西)。我无法让它正常工作 - 社区中有人有幸吗?
module JSONExample
open System
open System.IO
open System.Net
open System.Text
open System.Web
open System.Xml
open System.Security.Authentication
open System.Runtime.Serialization //add assemnbly reference System.Runtime.Serialization System.Xml
open System.Xml.Serialization
open System.Collections.Generic
[<DataContract>]
type ChemicalElementRecord = {
[<XmlAttribute("name")>]
[<field: DataMember(Name="name") >]
Name:string
[<XmlAttribute("name")>]
[<field: DataMember(Name="boiling_point") >]
BoilingPoint:string
[<XmlAttribute("atomic-mass")>]
[<field: DataMember(Name="atomic_mass") >]
AtomicMass:string
}
[<XmlRoot("freebase")>]
[<DataContract>]
type FreebaseResultRecord = {
[<XmlAttribute("code")>]
[<field: DataMember(Name="code") >]
Code:string
[<XmlArrayAttribute("results")>]
[<XmlArrayItem(typeof<ChemicalElementRecord>, ElementName = "chemical-element")>]
[<field: DataMember(Name="result") >]
Result: ChemicalElementRecord array
[<XmlElement("message")>]
[<field: DataMember(Name="message") >]
Message:string
}
let getJsonFromWeb() =
let query = "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]"
let query = query.Replace("'","\"")
let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}"
let request : HttpWebRequest = downcast WebRequest.Create(queryUrl)
request.Method <- "GET"
request.ContentType <- "application/x-www-form-urlencoded"
let response = request.GetResponse()
let result =
try
use reader = new StreamReader(response.GetResponseStream())
reader.ReadToEnd();
finally
response.Close()
let data = Encoding.Unicode.GetBytes(result);
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
stream
let test =
// get some JSON from the web
let stream = getJsonFromWeb()
// convert the stream of JSON into an F# Record
let JsonSerializer = Json.DataContractJsonSerializer(typeof<FreebaseResultRecord>)
let result: FreebaseResultRecord = downcast JsonSerializer.ReadObject(stream)
// save the Records to disk as JSON
use fs = new FileStream(@"C:\temp\freebase.json", FileMode.Create)
JsonSerializer.WriteObject(fs,result)
fs.Close()
// save the Records to disk as System Controlled XML
let xmlSerializer = DataContractSerializer(typeof<FreebaseResultRecord>);
use fs = new FileStream(@"C:\temp\freebase.xml", FileMode.Create)
xmlSerializer.WriteObject(fs,result)
fs.Close()
use fs = new FileStream(@"C:\temp\freebase-pretty.xml", FileMode.Create)
let xmlSerializer = XmlSerializer(typeof<FreebaseResultRecord>)
xmlSerializer.Serialize(fs,result)
fs.Close()
ignore(test)
Basically I want to have a single construct to deal with serializing to both JSON and formatted xml. Records worked nicely for serializing to/from json. However XmlSerializer requires a parameterless construtor. I don't really want to have to go through the exercise of building class objects for these constructs (principle only). I was hoping there could be some shortcut for getting a parameterless constructor onto a record (perhaps with a wioth statement or something). I can't get it to behave - has anybody in the community had any luck?
module JSONExample
open System
open System.IO
open System.Net
open System.Text
open System.Web
open System.Xml
open System.Security.Authentication
open System.Runtime.Serialization //add assemnbly reference System.Runtime.Serialization System.Xml
open System.Xml.Serialization
open System.Collections.Generic
[<DataContract>]
type ChemicalElementRecord = {
[<XmlAttribute("name")>]
[<field: DataMember(Name="name") >]
Name:string
[<XmlAttribute("name")>]
[<field: DataMember(Name="boiling_point") >]
BoilingPoint:string
[<XmlAttribute("atomic-mass")>]
[<field: DataMember(Name="atomic_mass") >]
AtomicMass:string
}
[<XmlRoot("freebase")>]
[<DataContract>]
type FreebaseResultRecord = {
[<XmlAttribute("code")>]
[<field: DataMember(Name="code") >]
Code:string
[<XmlArrayAttribute("results")>]
[<XmlArrayItem(typeof<ChemicalElementRecord>, ElementName = "chemical-element")>]
[<field: DataMember(Name="result") >]
Result: ChemicalElementRecord array
[<XmlElement("message")>]
[<field: DataMember(Name="message") >]
Message:string
}
let getJsonFromWeb() =
let query = "[{'type':'/chemistry/chemical_element','name':null,'boiling_point':null,'atomic_mass':null}]"
let query = query.Replace("'","\"")
let queryUrl = sprintf "http://api.freebase.com/api/service/mqlread?query=%s" "{\"query\":"+query+"}"
let request : HttpWebRequest = downcast WebRequest.Create(queryUrl)
request.Method <- "GET"
request.ContentType <- "application/x-www-form-urlencoded"
let response = request.GetResponse()
let result =
try
use reader = new StreamReader(response.GetResponseStream())
reader.ReadToEnd();
finally
response.Close()
let data = Encoding.Unicode.GetBytes(result);
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
stream
let test =
// get some JSON from the web
let stream = getJsonFromWeb()
// convert the stream of JSON into an F# Record
let JsonSerializer = Json.DataContractJsonSerializer(typeof<FreebaseResultRecord>)
let result: FreebaseResultRecord = downcast JsonSerializer.ReadObject(stream)
// save the Records to disk as JSON
use fs = new FileStream(@"C:\temp\freebase.json", FileMode.Create)
JsonSerializer.WriteObject(fs,result)
fs.Close()
// save the Records to disk as System Controlled XML
let xmlSerializer = DataContractSerializer(typeof<FreebaseResultRecord>);
use fs = new FileStream(@"C:\temp\freebase.xml", FileMode.Create)
xmlSerializer.WriteObject(fs,result)
fs.Close()
use fs = new FileStream(@"C:\temp\freebase-pretty.xml", FileMode.Create)
let xmlSerializer = XmlSerializer(typeof<FreebaseResultRecord>)
xmlSerializer.Serialize(fs,result)
fs.Close()
ignore(test)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这可以在 F# 版本 3.0 中通过使用 CLIMutable 属性。将其添加到无参数构造函数和读/写属性(而不是只读属性)的记录类型中。
This is possible in F# version 3.0 via use of the CLIMutable attribute. Add this to your record type for a parameterless constructor and read/write properties (instead of read only properties).
为什么不使用 DataContractSerializer(用于 Xml)而不是 XmlSerializer?这是数据契约的主要好处之一(多个投影的相同编程模型)。
(无法为 F# 记录创建无参数构造函数。)
Why not use the DataContractSerializer (for Xml) rather than XmlSerializer? That's one of the main benefits of data contracts (same programming model for multiple projections).
(There is no way to make a parameterless constructor for an F# record.)
看起来您无法将记录更改为类 - 或向其添加 edfault 构造函数。
提供的示例(基于本文:Link) 从 api.freebase.com 获取 json 流;然后我们反序列化为属性类;接下来将其作为 Json 序列化到磁盘;然后将其序列化为 Xml 到磁盘(使用 DataContract);最后,通过对输出的最佳控制,将其作为 Xml 序列化到磁盘(使用 XmlSerializer)
:
Looks like you can't change a record to a class - or add a edfault constructor to it.
The example provided (basedof off this article: Link) gets a stream of json from api.freebase.com; we then deserialize into the attributed classes; next serialize it as Json to disk; then serialize it as Xml to disk (using DataContract); finally, with the best controll of the output serialize it as Xml to disk (using XmlSerializer):
Notes: