在C#中反序列化进程创建指向父对象 [英] Create pointer to parent object in deserialization process in C#
问题描述
我有一个类,如:
[Serializable]
public class child {
public Parent parent;
}
[Serializable]
public class Parent {
public List<child> children;
}
当我反序列化父,我希望每个每个孩子有一个参考它的父。问题是,凡在反序列化过程中,我可以将孩子的父母指针?我似乎无法用于孩子的自定义构造函数,因为反序列化总是使用默认构造函数。如果我实现了ISerializable,则似乎子对象已经由创建父时创建的。有另一种方式来实现这一目标?
When I deserialize Parent, I want each of each children to have a reference to it's parent. Question is, where in the deserialization process can I set the child's "parent" pointer? I can't seem to use a custom constructor for child, because deserialization always uses the default constructor. If I implement ISerializable, then it seems that the child objects have already been created by the time the parent is created. Is there another way to achieve this?
推荐答案
循环引用是为处理不同的的BinaryFormatter
,的XmlSerializer
和的DataContractSerializer
。
Circular references are handled differently for the BinaryFormatter
, XmlSerializer
and DataContractSerializer
.
该 的BinaryFormatter
默认支持循环引用,不需要工作:
The BinaryFormatter
supports circular references by default, no work required:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Child
{
public Guid Id { get; set; }
public Parent parent;
}
[Serializable]
public class Parent
{
public Guid Id;
public List<Child> Children;
}
class Program
{
static void Main(string[] args)
{
Child c1 = new Child { Id = Guid.NewGuid() };
Child c2 = new Child { Id = Guid.NewGuid() };
Parent p = new Parent { Id = Guid.NewGuid(), Children = new List<Child> { c1, c2 } };
c1.parent = p;
c2.parent = p;
using (var stream1 = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream1, p);
stream1.Position = 0;
var deserializedParent = formatter.Deserialize(stream1) as Parent;
foreach (var child in deserializedParent.Children)
{
Console.WriteLine("Child Id: {0}, Parent Id: {1}", child.Id, child.parent.Id);
}
}
Console.ReadLine();
}
}
在使用的 的XmlSerializer
,避免圆形refernce通过不序列化孩子的引用父,并确保反序列化过程的关系是固定的。这是通过实施 的IXmlSerializable $ C $完成。C>
界面和处理序列化和反序列化
When using the XmlSerializer
, avoid the circular refernce by not serializing the child's reference to the parent and ensure that the relationship is fixed during the deserialization process. This is done by implementing the IXmlSerializable
interface and handling serialization and deserialization.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace XmlSerialization
{
[Serializable]
public class Child
{
public Guid Id { get; set; }
[XmlIgnore] // Don't serialize the reference to the parent
public Parent parent;
}
[Serializable]
public class Parent : IXmlSerializable
{
public List<Child> Children;
public Guid Id;
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XElement xml = XElement.ReadFrom(reader) as XElement;
if (xml != null)
{
// Deserialize Children
Children =
xml.Descendants("Child")
.Select(x => new Child() { Id = Guid.Parse(x.Element("Id").Value), parent = this })
.ToList();
// Deserialize Id
Id = Guid.Parse(xml.Attribute("Id").Value);
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
// Serialize Id
writer.WriteAttributeString("Id", Id.ToString());
// Serialize Children
XmlSerializer childSerializer = new XmlSerializer(typeof(Child));
foreach (Child child in Children)
{
childSerializer.Serialize(writer, child);
}
}
}
class Program
{
static void Main(string[] args)
{
Child c1 = new Child { Id = Guid.NewGuid() };
Child c2 = new Child { Id = Guid.NewGuid() };
Parent p = new Parent { Id = Guid.NewGuid(), Children = new List<Child> { c1, c2 } };
c1.parent = p;
c2.parent = p;
using (var stream1 = new MemoryStream())
{
XmlSerializer formatter = new XmlSerializer(typeof(Parent), new Type[] { typeof(Child) }) ;
formatter.Serialize(stream1, p);
stream1.Position = 0;
stream1.Position = 0;
var deserializedParent = formatter.Deserialize(stream1) as Parent;
foreach (var child in deserializedParent.Children)
{
Console.WriteLine(string.Format("Child Id: {0}, Parent Id: {1}", child.Id, child.parent.Id ));
}
}
Console.ReadLine();
}
}
}
在使用 的DataContractSerializer
,使用 IsReference 的财产 DataContract $ C $ 。C>属性,以使跟踪参考序列化和反序列化时DataContracts
When using the DataContractSerializer
, use the IsReference property of the DataContract
attribute to enable reference tracking when serializing and deserializing DataContracts.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[DataContract(IsReference = true)]
public class Child
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public Parent parent;
}
[DataContract(IsReference = true)]
public class Parent
{
[DataMember]
public Guid Id;
[DataMember]
public List<Child> Children;
}
class Program
{
static void Main(string[] args)
{
Child c1 = new Child { Id = Guid.NewGuid() };
Child c2 = new Child { Id = Guid.NewGuid() };
Parent p = new Parent { Id = Guid.NewGuid(), Children = new List<Child> { c1, c2 } };
c1.parent = p;
c2.parent = p;
using (var stream1 = new MemoryStream())
{
DataContractSerializer formatter = new DataContractSerializer(typeof(Parent));
formatter.WriteObject(stream1, p);
stream1.Position = 0;
var deserializedParent = formatter.ReadObject(stream1) as Parent;
foreach (var child in deserializedParent.Children)
{
Console.WriteLine("Child Id: {0}, Parent Id: {1}", child.Id, child.parent.Id);
}
}
Console.ReadLine();
}
}
这篇关于在C#中反序列化进程创建指向父对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!