尝试使用XMLSerialization序列化对象时,我收到以下异常。
A circular reference was detected while serializing an object of type MyObject}
我知道循环引用是因为ObjectA可以有childObject
的ObjectB而ObjectB的parentObject
是ObjectA,但是如果可能的话我想保留该引用。有没有办法让这个对象在XML序列化中序列化而不会在序列化过程中丢失任何数据?我对序列化并不熟悉,所以我希望我能设置一些属性。
答案 0 :(得分:25)
根据序列化程序类型,有几个选项。
如果您可以使用DataContractSerializer或BinaryFormatter,则可以使用OnSerializedAttribute并将子对象的Parent属性设置为:
[Serializable]
public class Child
{
public string Foo { get; set; }
public Parent Parent { get { return parent; } set { parent = value; } }
// We don't want to serialize this property explicitly.
// But we could set it during parent deserialization
[NonSerialized]
private Parent parent;
}
[Serializable]
public class Parent
{
// BinaryFormatter or DataContractSerializer whould call this method
// during deserialization
[OnDeserialized()]
internal void OnSerializedMethod(StreamingContext context)
{
// Setting this as parent property for Child object
Child.Parent = this;
}
public string Boo { get; set; }
public Child Child { get; set; }
}
class Program
{
static void Main(string[] args)
{
Child c = new Child { Foo = "Foo" };
Parent p = new Parent { Boo = "Boo", Child = c };
using (var stream1 = new MemoryStream())
{
DataContractSerializer serializer = new DataContractSerializer(typeof (Parent));
serializer.WriteObject(stream1, p);
stream1.Position = 0;
var p2 = (Parent)serializer.ReadObject(stream1);
Console.WriteLine(object.ReferenceEquals(p, p2)); //return false
Console.WriteLine(p2.Boo); //Prints "Boo"
//Prints: Is Parent not null: True
Console.WriteLine("Is Parent not null: {0}", p2.Child.Parent != null);
}
}
}
如果你想使用XmlSerializer,你应该实现IXmlSerializable,使用XmlIgnoreAttribute并在ReadXml方法中实现或多或少相同的逻辑。但在这种情况下,您还应手动实现所有Xml序列化逻辑:
[Serializable]
public class Child
{
public Child()
{
}
public string Foo { get; set; }
[XmlIgnore]
public Parent Parent { get; set; }
}
[Serializable]
public class Parent
{
public Parent()
{
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(System.Xml.XmlReader reader)
{
//Reading Parent content
//Reading Child
Child.Parent = this;
}
public void WriteXml(System.Xml.XmlWriter writer)
{
//Writing Parent and Child content
}
#endregion
public string Boo { get; set; }
public Child Child { get; set; }
}
答案 1 :(得分:2)
如果可以使用DataContractSerializer而不是XMLSerializer,则可以在DataContract属性上使用IsReference属性。启用它将保留引用,以便在反序列化时重新创建它们。
DataContractSerializer也会序列化为XML,但您对输出的外观稍有不足,您可以使用较旧的XMLSerializer。您可以在此处详细了解序列化程序:http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/
答案 2 :(得分:1)
将parentObject属性标记为[NonSerialized]。