F# 将构造函数添加到记录中?

发布于 2024-09-04 18:31:35 字数 3604 浏览 3 评论 0原文

基本上我想要一个单一的构造来处理 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

古镇旧梦 2024-09-11 18:31:35

Blockquote 我希望可以有一些快捷方式将无参数构造函数添加到记录中

这可以在 F# 版本 3.0 中通过使用 CLIMutable 属性。将其添加到无参数构造函数和读/写属性(而不是只读属性)的记录类型中。

Blockquote I was hoping there could be some shortcut for getting a parameterless constructor onto a record

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).

最美的太阳 2024-09-11 18:31:35

为什么不使用 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.)

百合的盛世恋 2024-09-11 18:31:35

看起来您无法将记录更改为类 - 或向其添加 edfault 构造函数。

提供的示例(基于本文:Link) 从 api.freebase.com 获取 json 流;然后我们反序列化为属性类;接下来将其作为 Json 序列化到磁盘;然后将其序列化为 Xml 到磁盘(使用 DataContract);最后,通过对输出的最佳控制,将其作为 Xml 序列化到磁盘(使用 XmlSerializer)

DataContract(系列)属性
DataContractJsonSerializer 和
JSON.DataContractJsonSerializer -
这些发生在类名上并且
成员变量。数据契约
事情很简单 - 而且
也适用于记录类型。

XmlSerializer(系列)属性
超越阶级和财产
吸气剂/吸气剂。这需要类型
是一个有默认值的对象
构造函数和属性 Getters 和
具有关联属性的设置器
他们每个人。如果房产没有
有 getter 或 setter
不会序列化 - 这是一个
惊喜(我想象默认的
讲师将确保
对象具有默认值
反序列化和设置者会
使用序列化的内容进行更新 -
但事实并非如此)。

另一个漂亮(叹息)的事情
XmlSerialization 是类
不能包含在模块内。所以
我们将类型移动到命名空间...

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)


    

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:

DataContract(family of) attributes for
DataContractJsonSerializer and
JSON.DataContractJsonSerializer -
these occur over the class names and
the memeber variables. DataContract
stuff was straight forward - and
works on record types as well.

XmlSerializer(family of) attributes
over the class and the Property
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. 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).

Another nifty (sigh) thing about
XmlSerialization is that the classes
can't be contained within a module. 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)


    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文