计算器异常时序列化类 [英] Stackoverflow Exception when serializing class

查看:151
本文介绍了计算器异常时序列化类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一棵树,想将它们序列化到XML。该节点从Nodebase类(在这里找到我认为),从而未能在序列推导

 公共类NodeBase:的IEqualityComparer,IEnumerable的,IEnumerable的< NodeBase> 
{

公共NodeBase家长{搞定;私人集; }

私人只读的IList< NodeBase>孩子=新的ObservableCollection< NodeBase>();

公共NodeBase这个[INT指数]
{
得到
{
返回this.children [指数]
}
}

公共无效的AddChild(NodeBase childNode,INT指数= -1)
{
如果(指数< -1)
{
抛出新的ArgumentException(指数不能低一些,然后-1);
}
如果(索引> this.Children.Count() - 1)
{
抛出新的ArgumentException(指数({0})不能高于。最后ITEN的指数使用addChild()方法没有一个指数底.FormatInvariant(指数))增加;
}
如果(!childNode.IsRoot)
{
抛出新的ArgumentException(与价值的子节点[{0}]不能添加,因为它不是根节点FormatInvariant(childNode.ToString()))。;
}

如果(this.Root == childNode)
{
抛出新的ArgumentException(与价值的子节点[{0}]是的的RootNode父FormatInvariant(childNode.ToString()))。。
}

如果(childNode.SelfAndDescendants.Any(N =>这== n))的
{
抛出新的ArgumentException(与值[在childNode {0}]不能添加到自身或其后代FormatInvariant(childNode.ToString()))。;
}

childNode.Parent =这一点;
如果(指数== -1)
{
this.children.Add(childNode);
}
,否则
{
this.children.Insert(索引,childNode);
}
}

公共无效AddChildren(PARAMS NodeBase []子节点)
{
的foreach(在子节点VAR childNode)
{
this.AddChild(childNode);
}
}

公共BOOL removeChild之(NodeBase节点)
{
返回this.children.Remove(节点);
}

公共无效AddFirstChild(NodeBase childNode)
{
this.AddChild(childNode,0);
}

公共无效AddFirstSibling(NodeBase childNode)
{
this.Parent.AddFirstChild(childNode);
}

公共无效AddLastSibling(NodeBase childNode)
{
this.Parent.AddChild(childNode);
}

公开的IEnumerable< NodeBase>叶
{
得到
{
返回this.Descendants.Where(N =>!n.Children.Any());
}
}

公共无效AddParent(NodeBase parentNode)
{
如果(!this.IsRoot)
{
抛出新的ArgumentException(这个节点[{0}]已经有一个父.FormatInvariant(this.ToString()),parentNode);
}
parentNode.AddChild(本);
}

公开的IEnumerable< NodeBase>祖先
{
得到
{
如果(this.IsRoot)
{
返回Enumerable.Empty< NodeBase>();
}
返回this.Parent.ToIEnumerable()CONCAT(this.Parent.Ancestors);
}
}

公开的IEnumerable< NodeBase>后人
{
得到
{
返回this.SelfAndDescendants.Skip(1);
}
}

公开的IEnumerable< NodeBase>儿童
{
得到
{
返回this.children;
}
}

公开的IEnumerable< NodeBase>兄弟姐妹
{
得到
{
返回this.SelfAndSiblings.Where(其它);
}
}

私人布尔其他(NodeBase节点)
{
返回的ReferenceEquals(节点,这一点)!;
}

公开的IEnumerable< NodeBase> SelfAndChildren
{
得到
{
返回this.ToIEnumerable()CONCAT(儿童)。
}
}

公开的IEnumerable< NodeBase> SelfAndAncestors
{
得到
{
返回this.ToIEnumerable()CONCAT(祖先)。
}
}

公开的IEnumerable< NodeBase> 。SelfAndDescendants
{
得到
{
返回this.ToIEnumerable()CONCAT(this.Children.SelectMany(C => c.SelfAndDescendants));
}
}

公开的IEnumerable< NodeBase> SelfAndSiblings
{
得到
{
如果(this.IsRoot)
{
返回this.ToIEnumerable();
}

返回this.Parent.Children;
}
}

公共NodeBase GetPreviousSibling()
{
返回this.GetPreviousSibling(本);
}

公共NodeBase GetPreviousSibling(NodeBase节点)
{
如果(this.Parent == NULL)
{
返回NULL;
}
VAR previousNode = this.Parent.Children.Reverse()SkipWhile(I =>!i.Equals(节点))
.Skip(1)
。 FirstOrDefault();
返回previousNode;
}

公共NodeBase GetPreviousNode()
{
VAR previousSibling = this.GetPreviousSibling();
如果(previousSibling!= NULL)
{
如果(this.HasChildren)
{
NodeBase电流=这一点;
,而(真)
{
VAR孩子= current.Children.Last();
如果(child.HasChildren!)
{
返回子女;
}
,否则
{
电流=子女;
}
}
}
,否则
{
返回previousSibling;
}
}
,否则
{
如果(this.HasParent)
{
返回this.Parent;
}
,否则
{
返回NULL;
}
}
}

公共NodeBase GetNextNode()
{
如果(this.HasChildren)
{
返回this.Children.First();
}
,否则
{
VAR nextSibling = this.GetNextSibling();
如果(nextSibling!= NULL)
{
返回nextSibling;
}
,否则
{
NodeBase电流=这一点;
NodeBase父母;
,而(真)
{
父= current.Parent;
如果(家长== NULL)
返回NULL;
,否则
{
VAR nextSibling2 = parent.GetNextSibling();
如果(nextSibling2!= NULL)
{
返回nextSibling2;
}
,否则
{
电流=父母;
}
}
}
}
}
}

公共BOOL HasParent
{
{返回this.Parent!= NULL; }
}

公共BOOL HasChildren
{
得到
{
返回this.children.Any();
}
}

公共NodeBase GetNextSibling()
{
返回this.GetNextSibling(本);
}

公共NodeBase GetNextSibling(NodeBase节点)
{
如果(this.Parent == NULL)
{
返回NULL;
}

VAR foundNode = this.Parent.Children.SkipWhile(I =>!i.Equals(节点));
VAR nextNode = foundNode.Skip(1)
.FirstOrDefault();
返回nextNode;
}

公开的IEnumerable< NodeBase>所有
{
获得
{
返回this.Root.SelfAndDescendants;
}
}

公开的IEnumerable< NodeBase> SameLevel
{
得到
{
返回this.SelfAndSameLevel.Where(其它);
}
}

公众诠释级别
{
得到
{
返回this.Ancestors.Count();
}
}

公开的IEnumerable< NodeBase> SelfAndSameLevel
{
得到
{
返回this.GetNodesAtLevel(级别);
}
}

公开的IEnumerable< NodeBase> GetNodesAtLevel(INT级)
{
返回this.Root.GetNodesAtLevelInternal(水平);
}

私人的IEnumerable< NodeBase> GetNodesAtLevelInternal(INT级)
{
如果(水平== this.Level)
{
返回this.ToIEnumerable();
}
返回this.Children.SelectMany(C => c.GetNodesAtLevelInternal(水平));
}

公共NodeBase根
{
得到
{
返回this.SelfAndAncestors.Last();
}
}

公共无效断开()
{
如果(this.IsRoot)
{
抛出新的InvalidOperationException异常(根节点[{0}]不能从父断开连接。FormatInvariant(this.ToString())。);
}
this.Parent.children.Remove(本);
this.Parent = NULL;
}

公共BOOL IsRoot
{
得到
{
返回this.Parent == NULL;
}
}

公共无效导线(动作< NodeBase>动作)
{
动作(本);
的foreach(VAR的孩子的孩子)
{
child.Traverse(动作);
}
}

公开的IEnumerable< NodeBase>拼合()
{
返回新的[] {}这.Union(children.SelectMany(X => x.Flatten()));
}

&的IEnumerator LT; NodeBase> IEnumerable的< NodeBase> .GetEnumerator()
{
返回this.children.GetEnumerator();
}

的IEnumerator IEnumerable.GetEnumerator()
{
返回this.children.GetEnumerator();
}

公众的IEnumerator< NodeBase>的GetEnumerator()
{
返回this.children.GetEnumerator();
}

私人静态布尔IsSameId< TID>(TID ID,TID parentId的?)
其中TID:结构
{
返回parentId的= NULL &功放;&安培; id.Equals(parentId.Value);
}

#区域为en = =

公共静态布尔运算符==(NodeBase值1,NodeBase值2)
{
如果((对象)(值)== NULL和放大器;及(对象)值2 == NULL)
{
返回真;
}
返回的ReferenceEquals(值1,值2);
}

公共静态布尔运算符=(NodeBase值1,NodeBase值2)
{
返回(值==值2);!
}

公众覆盖布尔等于(对象anderePeriode)
{
VAR valueThisType = anderePeriode为NodeBase;
返回此== valueThisType;
}

公共布尔等于(NodeBase值)
{
返回此==值;
}

公共布尔等于(NodeBase值1,NodeBase值2)
{
返回值1 ==值2;
}

布尔IEqualityComparer.Equals(对象值1,对象值2)
{
VAR valueThisType1 =值作为NodeBase;
VAR valueThisType2 =值作为NodeBase;

返回等于(valueThisType1,valueThisType2);
}

公众诠释的GetHashCode(obj对象)
{
返回的GetHashCode(OBJ为NodeBase);
}

公共覆盖INT的GetHashCode()
{
返回的GetHashCode(本);
}

公众诠释的GetHashCode(NodeBase值)
{
返回base.GetHashCode();
}

#endregion为en ==
}

首先串行建议,一个IEnumerable只能被序列化,当一个函数添加(System.Object的)的存在。为什么呢?



我添加一个虚拟函数
公共无效添加(目标节点)
{
}



和试图序列。我得到一个异常#1即可。
为什么,没有什么特别的在这个类。什么I'm做错了



 公共字符串SerializeToString< T>(T对象实例)
{
XmlSerializer的VAR =新的XmlSerializer(typeof运算(T));
VAR XML =新的StringBuilder();使用

(TextWriter的作家=新的StringWriter(XML))
{
xmlSerializer.Serialize(作家,对象实例);
}

返回xml.ToString();
}


解决方案

您正在运行到多重问题与的XmlSerializer



首先,的 的XmlSerializer 使得序列之间的一个区别的的和常规对象的。当序列化一个集合,只有集合中的项被序列化,集合类本身不是属性。否则,如果类的不是一个集合的属性将被序列化。这是在文档阐明:




可序列化项目



以下项目可使用XmlSerializer类序列化:




  • 公共读/写属性和公共类的领域。


  • 。实现的ICollection或IEnumerable的类



    注:
    只有集合是序列化,而不是公共属性


  • 的XmlElement对象。


  • XmlNode的对象。


  • 数据集对象。





NodeBase 同时类函数为节点和子节点的IEnumerable。正因为如此,的XmlSerializer 将不序列化派生类,这可能不是你想要的任何属性。相反,你需要提取一个单独的孩子属性,只列举&安培; 。序列化使用



(顺便说一下,让 NodeBase 实施的IEnumerable< NodeBase> 由于某种原因造成的构造的XmlSerializer 来使栈溢出,这让我吃惊 - 但即使这没有发生,您的代码将不能按的预期。)



其次,即使你通过一个子属性序列化的孩子,你会遇到另一个无限递归。这是因为的XmlSerializer 树串行的不是的图形串行的。所不同的是如下:




  1. 一个的图形串行的如的 的BinaryFormatter 递归下降从根对象开始的对象图被序列化。第一次遇到的物体,其序列在一个表中,它产生一个临时ID,和序列化在容器类的ID。如果串行器随后遇到同一个对象,它看起来它在表中,只是再次存储该运行时标识



    因此,环状对象图和曲线图,其中节点被多次引用,可序列化。


  2. A 乔木串行的如的 的XmlSerializer 较为有限。递归下降从根对象开始的对象图被序列化和遇到其序列的每个对象。如果遇到同样的对象两次,将序列化的两倍。如果遇到对象图中一个周期,的将陷入无限递归的。这是因为它希望和要求对象层次是一个纯粹的乔木




所以,在你的结构,你有:

 公共类NodeBase 
{

公共NodeBase家长{搞定;私人集; }

公开的IEnumerable< NodeBase>儿童
{
得到
{
返回this.children;
}
}
}



这两个属性是公共的,因此,序列化的。因此,根节点将递归序列的第一个孩子,而属性将的递归序列化父



要解决这个问题,标记所有比孩子其他的 NodeBase - 相关性< A HREF =http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributes.xmlignore%28v=vs.110%29.aspx相对=nofollow> [XmlIgnore] 。您还需要使用代理属性明确序列孩子作为一个数组:

 公共类NodeBase 
{
[XmlIgnore]
公共NodeBase家长{搞定;私人集; }

[XmlIgnore]
公开的IEnumerable< NodeBase>儿童
{
得到
{
返回this.children;
}
}

[XmlArray(孩子),可浏览(假),EditorBrowsable(EditorBrowsableState.Never)
公共NodeBase []的childList
{
得到
{
返回children.ToArray();
}

{
如果(!object.ReferenceEquals(值,this.children))
{
children.Clear();
的foreach(价值VAR的孩子)
的AddChild(小孩);
}
}
}
}

这将让你的树被序列化和反序列化。



(顺便说一句,做一个类 T 实施的IEqualityComparer< T> 是非常典型的。通常它实现 IEquatable< T> 和/或一些独立的比较器类实现的 的IEqualityComparer< T>


I have a tree and want to serialize them to xml. The nodes derive from a Nodebase class (found here I think), which fails on serializing.

public class NodeBase : IEqualityComparer, IEnumerable, IEnumerable<NodeBase>
{

    public NodeBase Parent { get; private set; }

    private readonly IList<NodeBase> children = new ObservableCollection<NodeBase>();

    public NodeBase this[int index]
    {
        get
        {
            return this.children[index];
        }
    }

    public void AddChild(NodeBase childNode, int index = -1)
    {
        if (index < -1)
        {
            throw new ArgumentException("The index can not be lower then -1");
        }
        if (index > this.Children.Count() - 1)
        {
            throw new ArgumentException("The index ({0}) can not be higher then index of the last iten. Use the AddChild() method without an index to add at the end".FormatInvariant(index));
        }
        if (!childNode.IsRoot)
        {
            throw new ArgumentException("The child node with value [{0}] can not be added because it is not a root node.".FormatInvariant(childNode.ToString()));
        }

        if (this.Root == childNode)
        {
            throw new ArgumentException("The child node with value [{0}] is the rootnode of the parent.".FormatInvariant(childNode.ToString()));
        }

        if (childNode.SelfAndDescendants.Any(n => this == n))
        {
            throw new ArgumentException("The childnode with value [{0}] can not be added to itself or its descendants.".FormatInvariant(childNode.ToString()));
        }

        childNode.Parent = this;
        if (index == -1)
        {
            this.children.Add(childNode);
        }
        else
        {
            this.children.Insert(index, childNode);
        }
    }

    public void AddChildren(params NodeBase[] childNodes)
    {
        foreach (var childNode in childNodes)
        {
            this.AddChild(childNode);
        }
    }

    public bool RemoveChild(NodeBase node)
    {
        return this.children.Remove(node);
    }

    public void AddFirstChild(NodeBase childNode)
    {
        this.AddChild(childNode, 0);
    }

    public void AddFirstSibling(NodeBase childNode)
    {
        this.Parent.AddFirstChild(childNode);
    }

    public void AddLastSibling(NodeBase childNode)
    {
        this.Parent.AddChild(childNode);
    }

    public IEnumerable<NodeBase> Leaves
    {
        get
        {
            return this.Descendants.Where(n => !n.Children.Any());
        }
    }

    public void AddParent(NodeBase parentNode)
    {
        if (!this.IsRoot)
        {
            throw new ArgumentException("This node [{0}] already has a parent".FormatInvariant(this.ToString()), "parentNode");
        }
        parentNode.AddChild(this);
    }

    public IEnumerable<NodeBase> Ancestors
    {
        get
        {
            if (this.IsRoot)
            {
                return Enumerable.Empty<NodeBase>();
            }
            return this.Parent.ToIEnumerable().Concat(this.Parent.Ancestors);
        }
    }

    public IEnumerable<NodeBase> Descendants
    {
        get
        {
            return this.SelfAndDescendants.Skip(1);
        }
    }

    public IEnumerable<NodeBase> Children
    {
        get
        {
            return this.children;
        }
    }

    public IEnumerable<NodeBase> Siblings
    {
        get
        {
            return this.SelfAndSiblings.Where(Other);
        }
    }

    private bool Other(NodeBase node)
    {
        return !ReferenceEquals(node, this);
    }

    public IEnumerable<NodeBase> SelfAndChildren
    {
        get
        {
            return this.ToIEnumerable().Concat(Children);
        }
    }

    public IEnumerable<NodeBase> SelfAndAncestors
    {
        get
        {
            return this.ToIEnumerable().Concat(Ancestors);
        }
    }

    public IEnumerable<NodeBase> SelfAndDescendants
    {
        get
        {
            return this.ToIEnumerable().Concat(this.Children.SelectMany(c => c.SelfAndDescendants));
        }
    }

    public IEnumerable<NodeBase> SelfAndSiblings
    {
        get
        {
            if (this.IsRoot)
            {
                return this.ToIEnumerable();
            }

            return this.Parent.Children;
        }
    }

    public NodeBase GetPreviousSibling()
    {
        return this.GetPreviousSibling(this);
    }

    public NodeBase GetPreviousSibling(NodeBase node)
    {
        if (this.Parent == null)
        {
            return null;
        }
        var previousNode = this.Parent.Children.Reverse().SkipWhile(i => !i.Equals(node))
                                           .Skip(1)
                                           .FirstOrDefault();
        return previousNode;
    }

    public NodeBase GetPreviousNode()
    {
        var previousSibling = this.GetPreviousSibling();
        if (previousSibling != null)
        {
            if (this.HasChildren)
            {
                NodeBase current = this;
                while (true)
                {
                    var child = current.Children.Last();
                    if (!child.HasChildren)
                    {
                        return child;
                    }
                    else
                    {
                        current = child;
                    }
                }
            }
            else
            {
                return previousSibling;
            }
        }
        else
        {
            if (this.HasParent)
            {
                return this.Parent;
            }
            else
            {
                return null;
            }
        }
    }

    public NodeBase GetNextNode()
    {
        if (this.HasChildren)
        {
            return this.Children.First();
        }
        else
        {
            var nextSibling = this.GetNextSibling();
            if (nextSibling != null)
            {
                return nextSibling;
            }
            else
            {
                NodeBase current = this;
                NodeBase parent;
                while (true)
                {
                    parent = current.Parent;
                    if (parent == null)
                        return null;
                    else
                    {
                        var nextSibling2 = parent.GetNextSibling();
                        if (nextSibling2 != null)
                        {
                            return nextSibling2;
                        }
                        else
                        {
                            current = parent;
                        }
                    }
                }
            }
        }
    }

    public bool HasParent
    {
        get { return this.Parent != null; }
    }

    public bool HasChildren
    {
        get
        {
            return this.children.Any();
        }
    }

    public NodeBase GetNextSibling()
    {
        return this.GetNextSibling(this);
    }

    public NodeBase GetNextSibling(NodeBase node)
    {
        if (this.Parent == null)
        {
            return null;
        }

        var foundNode = this.Parent.Children.SkipWhile(i => !i.Equals(node));
        var nextNode = foundNode.Skip(1)
                                .FirstOrDefault();
        return nextNode;
    }

    public IEnumerable<NodeBase> All
    {
        get
        {
            return this.Root.SelfAndDescendants;
        }
    }

    public IEnumerable<NodeBase> SameLevel
    {
        get
        {
            return this.SelfAndSameLevel.Where(Other);
        }
    }

    public int Level
    {
        get
        {
            return this.Ancestors.Count();
        }
    }

    public IEnumerable<NodeBase> SelfAndSameLevel
    {
        get
        {
            return this.GetNodesAtLevel(Level);
        }
    }

    public IEnumerable<NodeBase> GetNodesAtLevel(int level)
    {
        return this.Root.GetNodesAtLevelInternal(level);
    }

    private IEnumerable<NodeBase> GetNodesAtLevelInternal(int level)
    {
        if (level == this.Level)
        {
            return this.ToIEnumerable();
        }
        return this.Children.SelectMany(c => c.GetNodesAtLevelInternal(level));
    }

    public NodeBase Root
    {
        get
        {
            return this.SelfAndAncestors.Last();
        }
    }

    public void Disconnect()
    {
        if (this.IsRoot)
        {
            throw new InvalidOperationException("The root node [{0}] can not get disconnected from a parent.".FormatInvariant(this.ToString()));
        }
        this.Parent.children.Remove(this);
        this.Parent = null;
    }

    public bool IsRoot
    {
        get
        {
            return this.Parent == null;
        }
    }

    public void Traverse(Action<NodeBase> action)
    {
        action(this);
        foreach (var child in children)
        {
            child.Traverse(action);
        }
    }

    public IEnumerable<NodeBase> Flatten()
    {
        return new[] { this }.Union(children.SelectMany(x => x.Flatten()));
    }

    IEnumerator<NodeBase> IEnumerable<NodeBase>.GetEnumerator()
    {
        return this.children.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.children.GetEnumerator();
    }

    public IEnumerator<NodeBase> GetEnumerator()
    {
        return this.children.GetEnumerator();
    }

    private static bool IsSameId<TId>(TId id, TId? parentId)
        where TId : struct
    {
        return parentId != null && id.Equals(parentId.Value);
    }

    #region Equals en ==

    public static bool operator ==(NodeBase value1, NodeBase value2)
    {
        if ((object)(value1) == null && (object)value2 == null)
        {
            return true;
        }
        return ReferenceEquals(value1, value2);
    }

    public static bool operator !=(NodeBase value1, NodeBase value2)
    {
        return !(value1 == value2);
    }

    public override bool Equals(Object anderePeriode)
    {
        var valueThisType = anderePeriode as NodeBase;
        return this == valueThisType;
    }

    public bool Equals(NodeBase value)
    {
        return this == value;
    }

    public bool Equals(NodeBase value1, NodeBase value2)
    {
        return value1 == value2;
    }

    bool IEqualityComparer.Equals(object value1, object value2)
    {
        var valueThisType1 = value1 as NodeBase;
        var valueThisType2 = value2 as NodeBase;

        return Equals(valueThisType1, valueThisType2);
    }

    public int GetHashCode(object obj)
    {
        return GetHashCode(obj as NodeBase);
    }

    public override int GetHashCode()
    {
        return GetHashCode(this);
    }

    public int GetHashCode(NodeBase value)
    {
        return base.GetHashCode();
    }

    #endregion Equals en ==
}

First the serializer advises that an IEnumerable can only be serialized, when a function Add(System.Object) exists. Why?

I add a dummy function public void Add(object node) { }

and tried to serialize. I get a Stackoverflow exception then. Why, there is nothing special in this class. What I´m doing wrong?

 public string SerializeToString<T>(T objectInstance)
{
var xmlSerializer = new XmlSerializer(typeof(T));
var xml = new StringBuilder();

using (TextWriter writer = new StringWriter(xml))
{
    xmlSerializer.Serialize(writer, objectInstance);
}

return xml.ToString();
}

解决方案

You are running into multiple problems with XmlSerializer.

Firstly, XmlSerializer makes a distinction between serializing a collection and a regular object. When serializing a collection, only the items in the collection are serialized, not the properties of the collection class itself. Otherwise if the class is not a collection the properties will be serialized. This is spelled out in the documentation:

Items That Can Be Serialized

The following items can be serialized using the XmLSerializer class:

  • Public read/write properties and fields of public classes.

  • Classes that implement ICollection or IEnumerable.

    Note: Only collections are serialized, not public properties.

  • XmlElement objects.

  • XmlNode objects.

  • DataSet objects.

Your NodeBase class functions simultaneously as a node and an IEnumerable of child nodes. Because of this, XmlSerializer won't serialize any properties of derived classes, which is probably not what you want. Instead, you need to extract a separate Children property, and only enumerate & serialize using that.

(Incidentally, making NodeBase implement IEnumerable<NodeBase> is somehow causing the constructor for XmlSerializer to overflow the stack. That surprises me -- but even if that didn't happen, your code would not work as expected.)

Secondly, even if you serialize the children via a child property, you will encounter yet another infinite recursion. That's because XmlSerializer is a tree serializer not a graph serializer. The difference is as follows:

  1. A graph serializer such as BinaryFormatter recursively descends the object graph starting from the root object being serialized. The first time it encounters an object, it serializes it in a table, generates a temporary ID for it, and serializes the ID in the container class. If the serializer encounters the same object subsequently, it looks it up in the table and simply stores the run-time ID again.

    Thus, cyclic object graphs and graphs where nodes are referenced multiple times can be serialized.

  2. A tree serializer such as XmlSerializer is more limited. It recursively descends the object graph starting from the root object being serialized and serializes each object as it is encountered. If it encounters the same object twice, it will serialize it twice. If it encounters a cycle in the object graph, it will fall into infinite recursion. That's because it expects and requires the object hierarchy to be a pure tree.

So, in your structure, you have:

public class NodeBase 
{

    public NodeBase Parent { get; private set; }

    public IEnumerable<NodeBase> Children
    {
        get
        {
            return this.children;
        }
    }
}

Both these properties are public and thus serializable. So, the root node will recursively serialize its first child, and the Parent property will recursively serialize the parent.

To fix this, mark all the NodeBase-related properties other than the Children as [XmlIgnore]. You'll also need to serialize the children explicitly as an array using a proxy property:

public class NodeBase 
{
    [XmlIgnore]
    public NodeBase Parent { get; private set; }

    [XmlIgnore]
    public IEnumerable<NodeBase> Children
    {
        get
        {
            return this.children;
        }
    }

    [XmlArray("Children"), Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public NodeBase [] ChildList
    {
        get
        {
            return children.ToArray();
        }
        set
        {
            if (!object.ReferenceEquals(value, this.children))
            {
                children.Clear();
                foreach (var child in value)
                    AddChild(child);
            }
        }
    }
}

This will allow your tree to be serialized and deserialized.

(Incidentally, making a class T implement IEqualityComparer<T> is very atypical. Usually it implements IEquatable<T> and/or some separate comparer class implements IEqualityComparer<T>.)

这篇关于计算器异常时序列化类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆