在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;
}
}
}
从发布的代码的快速运行中,跳出的问题是您正在运行反序列化的示例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
中手动初始化这些。