代码之家  ›  专栏  ›  技术社区  ›  Rachel

使用XML序列化时循环引用?

  •  20
  • Rachel  · 技术社区  · 14 年前

    A circular reference was detected while serializing an object of type MyObject}

    我知道循环引用是因为ObjectA可以有 childObject ObjectB和ObjectB的 parentObject 是ObjectA,但是如果可能的话,我想保留该引用。有没有一种方法可以让这个对象通过XML序列化进行序列化,而不会在序列化过程中丢失任何数据?我对序列化不是很熟悉,所以我希望可以设置某种属性。

    3 回复  |  直到 14 年前
        1
  •  26
  •   Sergey Teplyakov    14 年前

    根据序列化程序类型,有几个选项。

    如果你能用 DataContractSerializer BinaryFormatter 那你可以用 OnSerializedAttribute 并将子对象的父属性设置为:

    [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; }
    }
    
        2
  •  2
  •   AHM    14 年前

    如果可以使用DataContractSerializer而不是XMLSerializer,则可以在DataContract属性上使用IsReference属性。启用此选项将保留引用,以便在反序列化时重新创建它们。

    DataContractSerializer也可以序列化为XML,但是您对输出的控制要比使用旧的XMLSerializer少一些。您可以在此处阅读有关序列化程序的更多信息: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/

        3
  •  1
  •   Andrew Roberts slawekwin    4 年前

    将parentObject属性标记为[NonSerialized]。

    https://blog.kowalczyk.info/article/8n/serialization-in-c.html