在C#中反序列化过程中创建指向父对象的指针

我有一个类:

[Serializable] public class child { public Parent parent; } [Serializable] public class Parent { public List children; } 

当我反序列化Parent时,我希望每个孩子都有一个对它的父级的引用。 问题是,在反序列化过程中我可以设置子项的“父”指针吗? 我似乎无法为子进程使用自定义构造函数,因为反序列化始终使用默认构造函数。 如果我实现了ISerializable,那么似乎在创建父级时已经创建了子对象。 有没有其他方法来实现这一目标?

对于BinaryFormatterXmlSerializerDataContractSerializer ,循环引用的处理方式不同。

BinaryFormatter默认支持循环引用,无需工作:

 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 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 { 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 ,不要通过序列化子对父对象的引用来避免循环引用,并确保在反序列化过程中修复关系。 这是通过实现IXmlSerializable接口并处理序列化和反序列化来完成的。

 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 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 { 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 ,使用DataContract属性的IsReference属性在序列化和反序列化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 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 { 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(); } } 

如果不管它并让Parent成为Child类的公共读/写属性,.NET自动序列化过程将正确处理它。

如果自动反序列化不起作用,您可以让Parent类实现IDeserializationCallback接口 ,并更新OnDeserialization方法中的子项 。

 [Serializable] class Parent : IDeserializationCallback { public List children; void IDeserializationCallback.OnDeserialization(Object sender) { if (null != children) { children.ForEach(c => c.parent = this); } } } 

我通过覆盖子对象的集合类中的Add方法来完成这种(某种),使用父对象的唯一标识符“设置”子类中的属性值。

  public class Connections: List { public new void Add(Connection connection) { connection.ApplicationName = ApplicationName; base.Add(connection); } }