c# - mvc - a circular reference was detected while serializing an object of type
¿Referencia circular al usar serialización XML? (3)
Recibo la siguiente excepción al intentar serializar un objeto utilizando XMLSerialization.
A circular reference was detected while serializing an object of type MyObject}
Sé que la referencia circular es porque ObjectA puede tener un childObject
de ObjectB y ObjectB''s parentObject
es ObjectA, sin embargo, me gustaría mantener esa referencia si es posible. ¿Hay alguna forma de que este objeto se serialice con la serialización XML sin perder ningún dato durante el proceso de serialización? No estoy muy familiarizado con la serialización, así que espero que haya algún tipo de atributo que pueda establecer.
Hay varias opciones dependiendo del tipo de serializador.
Si puede usar DataContractSerializer o BinaryFormatter entonces puede usar OnSerializedAttribute y establecer la propiedad Parent para su objeto secundario a esto:
[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);
}
}
}
Si desea usar XmlSerializer , debe implementar IXmlSerializable , usar XmlIgnoreAttribute e implementar más o menos la misma lógica en el método ReadXml. Pero en este caso, también debe implementar manualmente toda la lógica de serialización 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; }
}
Marque la propiedad parentObject como [NonSerialized].
Si puede usar el DataContractSerializer en lugar del XMLSerializer, entonces puede usar la propiedad IsReference en el atributo DataContract. Al habilitar esto, se mantendrán las referencias, de modo que se volverán a crear después de la deserialización.
El DataContractSerializer también se serializa a XML, pero tiene un poco menos control sobre cómo se ve la salida, que con el XMLSerializer anterior. Puede leer más sobre los serializadores aquí: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/