【问题标题】:How can I fix circular A circular reference was detected while serializing?如何修复循环序列化时检测到循环引用?
【发布时间】:2014-02-26 23:28:45
【问题描述】:

我正在尝试使用下面提供的对象序列化树结构。我需要用对象序列化子列表,但我可以没有父(因为我可以在反序列化时修复它)。

我遇到的问题是,无论我是否有[XmlIgnore],我仍然会收到此错误。

序列化类型对象时检测到循环引用 '数据输入'

如果我将“父”属性的“getter/setter”更改为不执行任何操作,则一切正常。

[XmlIgnore]
        public DataEntry Parent 
        {
            get { return null; }
            set {} 
        }

但我需要在稍后阶段提供此父参考。

public class DataEntry
    {
        [XmlIgnore]
        public DataEntry Parent { get; set; }

        public List<DataEntry> Children { get; set; }

        private List<String> mValues = new List<String>();
        public List<String> Values
        {
            get
            {
                return mValues;
            }
            set
            {
                mValues = value;
            }
        }

        private String mName = String.Empty;
        public String Name
        {
            get { return mName; }
            set
            {
                mName = value;
            }
        }

        /// <summary>
        /// Data entry
        /// </summary>
        /// <param name="partent">parent node - if root node give no parent</param>
        /// <param name="name">Name of property</param>
        /// <param name="values">Values for this property</param>
        public DataEntry(DataEntry partent, String name, List<String> values)
        {
            Children = new List<DataEntry>(); 
            Parent = partent;
            mValues = values;
            mName = name;
        }

        /// <summary>
        /// Add a child to this node
        /// </summary>
        /// <param name="child"></param>
        public void AddChild(DataEntry child)
        {
            Children.Add(child);
        }
    }

任何帮助将不胜感激。

【问题讨论】:

  • 在将解决方案发布到全世界后,始终以您找到解决方案的方式。因此,要使 Xml 标记正常工作,我需要将其更改为 [ScriptIgnore]。对此的引用位于System.Web.Extentions 下,命名空间为System.Web.Script.Serialization

标签: c# serialization circular-dependency


【解决方案1】:

XML 具有树结构(嵌套标签)。您的对象以图的形式连接起来(即带有循环)。

您必须访问图表,找到循环并通过剪切参考打开它们。 一旦获得了图的生成树,就可以对其进行序列化。

但是被剪裁的引用会丢失。 因此,除了生成树之外,您还需要将剪裁的引用存储到。

在反序列化时,您需要反序列化生成树,然后再反序列化被剪裁的其他引用。因此,您将通过在对象之间重新建立这些引用来重建它们。

如果可以,请尽量避免图形中出现循环,方法是将其减少到定义中已经存在的生成树。这样您就不必为了序列化它而做所有这些工作。

另一方面,删除这些引用可能会影响应用程序的其余部分,因此您可能不想这样做。

另一方面:一个设计良好的数据库有一个normal form(通常是第三个​​,但也有其他的)。这些概念彼此之间非常相关。

这是一个粗略的伪 C# 指南:

xml = serialize(root)
{
    1. set all parents to null
    2. XML serialize
    3. rebuilt all parents <-- reuse rebuiltParents()
}

root = deserialize(xml)
{
    1. XML deserialize
    2. rebuilt all parents <-- reuse rebuiltParents()
}

【讨论】:

  • 那么你是说我需要在消毒之前手动移除父节点?所以我正确使用了 Xml 标签?
  • 不,不是父母,而是周期。您可以在任何时候剪辑一个循环,您必须找到取决于数据结构的最佳位置。等一下,也许我可以帮忙。
  • 嗯,是的...将所有父母设置为空,然后序列化。之后,通过设置实际的父母来重建树。反序列化时,您将获得没有父级的同一棵树,因此您可以将 rebuilt parents 功能放在函数 rebuiltParents() 中并使用它两次:在序列化之后和反序列化之后。我希望这是有道理的:)
  • 酷,谢谢。是的,所有节点在树中都是唯一的,因此 node1 -> node2 -> node3 -> node1 在任何时候都没有机会。一个节点被多次引用的唯一时间是父引用。
  • 是的,我只是不明白为什么 Xml 标签会起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多