我有一个类:
[Serializable] public class child { public Parent parent; } [Serializable] public class Parent { public Listchildren; }
当我反序列化Parent时,我希望每个孩子都有一个对它的父级的引用.问题是,在反序列化过程中我可以设置孩子的"父"指针吗?我似乎无法为子项使用自定义构造函数,因为反序列化始终使用默认构造函数.如果我实现了ISerializable,那么似乎在创建父级时已经创建了子对象.还有另一种方法来实现这一目标吗?
循环引用的处理方式不同BinaryFormatter
,XmlSerializer
和DataContractSerializer
.
该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 ListChildren; } 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 ListChildren; 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
,使用属性的IsReference属性DataContract
在序列化和反序列化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 ListChildren; } 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(); } }