在OnSerializing期间,能够避免基于引用对象的默认值,OnDeserialized失败

时间:2014-06-23 16:45:09

标签: c# xml-serialization datacontractserializer

我有一个具有默认值的参考对象,我不希望在序列化时写下这些默认值,这非常有效。

当我在Deserialize期间使用相同的逻辑时,我收到错误。我的目标是避免编写和读取默认值。

以下是有效的示例代码。

this.parenttext = m_rp.parenttext;
//this.parenttext = "Default Value for Parent";

this.childtext = m_rp.Child[m_count].childtext;
//this.childtext = "Default Value for Child";

以下是不起作用的示例代码。

//this.parenttext = m_rp.parenttext;
this.parenttext = "Default Value for Parent";

//this.childtext = m_rp.Child[m_count].childtext;
this.childtext = "Default Value for Child";

完整代码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Runtime.Serialization;

static class Module1
{


    public static void Main()
    {
        ReferenceParent rp = new ReferenceParent();
        PublicParent p = new PublicParent(rp);
        p.parenttext = "Default Value for Parent";
        p.Child[0].childtext = "Default Value for Child0";
        p.Child[1].childtext = "Default Value for Child1";

        p.parenttext = "Non-default Value for Parent";
        p.Child[0].childtext = "Non-default Value for Child0";
        p.Child[1].childtext = "Non-default Value for Child1";

        string xmlstring = null;

        XmlWriterSettings xmlws = new XmlWriterSettings();
        using (StringWriter sw = new StringWriter())
        {
            DataContractSerializer dcs1 = new DataContractSerializer(typeof(PublicParent));
            xmlws.Indent = true;
            xmlws.OmitXmlDeclaration = true;
            using (XmlWriter xwriter = XmlWriter.Create(sw, xmlws))
            {
                dcs1.WriteObject(xwriter, p);
                xwriter.Flush();
                xmlstring = sw.ToString();
            }
        }

        xmlstring = "<Parent xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://schemas.datacontract.org/2004/07/\">\r\n  <Child>\r\n    <Child />\r\n    <Child />\r\n  </Child>\r\n</Parent>";

        DataContractSerializer dcs2 = new DataContractSerializer(typeof(PublicParent));
        using (StringReader sr = new StringReader(xmlstring))
        {
            using (XmlReader xreader = XmlReader.Create(sr))
            {
                p = (PublicParent)dcs2.ReadObject(xreader);
            }
        }

    }

    [DataContract(Name = "Parent")]
    private class PublicParent
    {
        ReferenceParent m_rp;
        [DataMember(EmitDefaultValue = false)]
        private string m_parenttext;

        public string parenttext;
        [DataMember()]

        public PublicChild[] Child = new PublicChild[2];
        [OnSerializing()]
        private void OnSerializing(StreamingContext context)
        {
            if (this.parenttext == m_rp.parenttext)
             //if (this.parenttext == "Default Value for Parent")
            {
                this.m_parenttext = null;
            }
            else
            {
                this.m_parenttext = this.parenttext;
            }
        }

        [OnDeserialized()]
        private void OnDeserialized(StreamingContext context)
        {
            if (string.IsNullOrWhiteSpace(this.m_parenttext))
            {
                this.parenttext = m_rp.parenttext;
                //this.parenttext = "Default Value for Parent";
            }
            else
            {
                this.parenttext = this.m_parenttext;
            }
        }

        public PublicParent(ReferenceParent rp)
        {
            m_rp = rp;
            int count;
            for (count = 0; count <= 1; count++)
            {
                Child[count] = new PublicChild(rp, count);
            }
        }

        [DataContract(Name = "Child")]
        public class PublicChild
        {
            ReferenceParent m_rp;

            int m_count;
            [DataMember(EmitDefaultValue = false)]
            private string m_childtext;

            public string childtext;
            [OnSerializing()]
            private void OnSerializing(StreamingContext context)
            {
                if (this.childtext == m_rp.Child[m_count].childtext)
                //if (this.childtext == "Default Value for Child")
                {
                    this.m_childtext = null;
                }
                else
                {
                    this.m_childtext = this.childtext;
                }
            }

            [OnDeserialized()]
            private void OnDeserialized(StreamingContext context)
            {
                if (string.IsNullOrWhiteSpace(this.m_childtext))
                {
                    this.childtext = m_rp.Child[m_count].childtext;
                    //this.childtext = "Default Value for Child";
                }
                else
                {
                    this.childtext = this.m_childtext;
                }
            }

            public PublicChild(ReferenceParent rp, int count)
            {
                m_rp = rp;
                m_count = count;
            }
        }
    }

    [DataContract()]
    private class ReferenceParent
    {
        public string parenttext;
        [DataMember()]

        public ReferenceChild[] Child = new ReferenceChild[2];
        public ReferenceParent()
        {
            parenttext = "Default Value for Parent";
            int count;
            for (count = 0; count <= 1; count++)
            {
                Child[count] = new ReferenceChild();
                Child[count].childtext = "Default Value for Child" + count.ToString();
            }
        }

        [DataContract()]
        public class ReferenceChild
        {
            public string childtext;
        }
    }

}

1 个答案:

答案 0 :(得分:0)

从快速发布的代码中,跳出来的是你运行反序列化的示例xml代码字符串与序列化的xml字符串的格式不匹配。

序列化实例的输出结果为:

<Parent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/MyTypeNamespace">
  <Child>
    <Child />
    <Child />
  </Child>
</Parent>

(其中MyTypeNamesapce是该类型的c#名称空间)

而您正在运行反序列化的xml片段是

<Parent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
    <Child>
        <Child />
        <Child />
    </Child>
</Parent>

请注意默认命名空间的差异。默认情况下,DataContractSerializer会将类型的名称空间附加到http://schemas.datacontract.org/2004/07/的默认名称。

可能这只是你发布代码片段的神器。 名称是否一致,你也可以发布例外吗?

[编辑 - 回应OP的评论]

注释掉你建议的行后,我也得到一个NullReferenceException。

这里的问题是PublicChild.m_rp字段在反序列化时为null。 在创建序列化实例时,可以使用PublicChild(ReferenceParent rp, int count)构造函数中的PublicParent(ReferenceParent rp)构造函数。 在反序列化时,这些构造函数不会被调用,因此该字段将为null。你需要以某种方式迎合它;可能是通过在OnDeserialized

中手动初始化这些内容