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

本文关键字:引用 对象 默认值 失败 OnDeserialized 于引用 期间 OnSerialization | 更新日期: 2023-09-27 18:09:52

我有一个引用对象,它有默认值,我不想在序列化时写入这些默认值,这非常有效。

当我在反序列化过程中使用相同的逻辑时,我会出错。我的目标是避免写入和读取默认值。

以下是有效的示例代码。

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;
        }
    }
}

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

从发布的代码的快速运行中,跳出的问题是您正在运行反序列化的示例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/的默认名称空间。

这可能是你发布代码片段的产物。名称一致吗?你也能发布异常吗?

[EDIT-回应OP的评论]

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

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