[英]F# Add Constructor to a Record?
Basically I want to have a single construct to deal with serializing to both JSON and formatted xml. 基本上,我希望有一个结构来处理序列化为JSON和格式化的xml。 Records worked nicely for serializing to/from json.
记录可以很好地用于从json序列化到/从json序列化。 However XmlSerializer requires a parameterless construtor.
但是,XmlSerializer需要无参数的构造函数。 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)
Blockquote I was hoping there could be some shortcut for getting a parameterless constructor onto a record
我希望Blockquote能够为将无参数构造函数添加到记录中提供一些捷径
This is possible in F# version 3.0 via use of the CLIMutable attribute. 在F#3.0版中,可以通过使用CLIMutable属性来实现。 Add this to your record type for a parameterless constructor and read/write properties (instead of read only properties).
将其添加到无参数构造函数和读/写属性(而不是只读属性)的记录类型中。
Why not use the DataContractSerializer (for Xml) rather than XmlSerializer? 为什么不使用DataContractSerializer(用于Xml)而不是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.) (无法为F#记录创建无参数构造函数。)
Looks like you can't change a record to a class - or add a edfault constructor to it. 看起来您无法将记录更改为类-或向其中添加edfault构造函数。
The example provided (basedof off this article: http://blogs.msdn.com/b/jomo_fisher/archive/2010/03/06/neat-sample-f-and-freebase.aspx ) gets a stream of json from api.freebase.com; 提供的示例(基于本文: http : //blogs.msdn.com/b/jomo_fisher/archive/2010/03/06/neat-sample-f-and-freebase.aspx )从api获取json流.freebase.com; we then deserialize into the attributed classes;
然后我们反序列化为归因的类; next serialize it as Json to disk;
接下来将其序列化为Json到磁盘; then serialize it as Xml to disk (using DataContract);
然后将其序列化为Xml到磁盘(使用DataContract); finally, with the best controll of the output serialize it as Xml to disk (using XmlSerializer):
最后,最好地控制输出,将其序列化为Xml到磁盘(使用XmlSerializer):
Notes: 笔记:
DataContract(family of) attributes for DataContractJsonSerializer and JSON.DataContractJsonSerializer - these occur over the class names and the memeber variables.
DataContractJsonSerializer和JSON.DataContractJsonSerializer的DataContract(family of)属性-这些发生在类名称和成员变量上。 DataContract stuff was straight forward - and works on record types as well.
DataContract的内容非常简单-并适用于记录类型。
XmlSerializer(family of) attributes over the class and the Property Getter/Setter.
XmlSerializer(family of)类和属性Getter / Setter的属性。 This requires the type is an object with a default constructor, and property Getters and Setters w/ attributes associated with each of them.
这就要求该类型是一个具有默认构造函数的对象,以及具有与它们各自关联的属性的属性Getters和Setters。 If a Property doesn't have eitehr a getter or a setter it will not serialize - which was a suprise (I imagined the default onstructor would ensure that the object had defulat values upon deserialization and the setters would update with whatever was serialized - but no this isn't the case).
如果Property没有egethr或setter,它将不会序列化-这是一个意外(我想默认的构造函数将确保对象在反序列化时具有defulat值,并且setter将使用序列化的内容进行更新-但没有并非如此)。
Another nifty (sigh) thing about XmlSerialization is that the classes can't be contained within a module.
约XmlSerialization另一个漂亮 (叹气)事情是,类不能被包含在一个模块内。 So we move the types up to a namespace...
因此,我们将类型移至名称空间...
namespace 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() =
[<field: DataMember(Name="name") >]
let mutable name: string = ""
[<field: DataMember(Name="boiling_point") >]
let mutable boilingPoint: string =""
[<field: DataMember(Name="atomic_mass") >]
let mutable atomicMass: string = ""
[<XmlAttribute("name")>]
member this.Name with get() = name and set v = name <- v
[<XmlAttribute("boiling-point")>]
member this.BoilingPoint with get() = boilingPoint and set v = boilingPoint <- v
[<XmlAttribute("atomic-mass")>]
member this.AtomicMass with get() = atomicMass and set v = atomicMass <- v
[<XmlRoot("freebase")>]
[<DataContract>]
type FreebaseResultRecord() =
[<field: DataMember(Name="code") >]
let mutable code: string = ""
[<field: DataMember(Name="result") >]
let mutable result: ChemicalElementRecord array = Array.empty
[<field: DataMember(Name="message") >]
let mutable message: string = ""
[<XmlElement("message")>]
member this.Message with get() : string = message and set v = message <- v
[<XmlArrayAttribute("chemical-elements")>]
[<XmlArrayItem(typeof<ChemicalElementRecord>, ElementName = "chemical-element")>]
member this.Result with get() = result and set v = result <- v
[<XmlAttribute("code")>]
member this.Code with get() = code and set v = code <- v
module Test =
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.