Joh*_*o75 2 c# exception xmlserializer
我有一棵树,想要将它们序列化为xml.节点派生自Nodebase类(我认为在这里找到),它在序列化时失败.
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 ==
}
首先,当存在函数Add(System.Object)时,序列化程序建议只能序列化IEnumerable.为什么?
我添加了一个虚函数public void Add(object node){}
并试图序列化.我得到一个Stackoverflow异常.为什么,这堂课没什么特别之处.我做错了什么?
 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();
}
你遇到了多个问题XmlSerializer.
首先,XmlSerializer区分序列化集合和常规对象.序列化集合时,只序列化集合中的项目,而不是集合类本身的属性.否则,如果该类不是集合,则将序列化属性.这在文档中有详细说明:
可以序列化的项目
可以使用XmLSerializer类序列化以下项:
公共读/写属性和公共类的字段.
实现ICollection或IEnumerable的类.
注意: 仅序列化集合,而不是公共属性.
XmlElement对象.
XmlNode对象.
DataSet对象.
您的NodeBase类同时作为节点和IEnumerable子节点运行.因此,XmlSerializer不会序列化派生类的任何属性,这可能不是您想要的.相反,您需要提取一个单独的Children属性,并且只使用它进行枚举和序列化.
(顺便说一下,制作NodeBase工具IEnumerable<NodeBase>会以某种方式导致构造函数XmlSerializer溢出堆栈.这让我感到惊讶 - 但即使没有发生,你的代码也无法正常工作.)
其次,即使您通过子属性序列化子项,您将遇到另一个无限递归.这是因为   XmlSerializer是树序列化不是一个图形序列化.区别如下:
甲图表串行如BinaryFormatter递归下降从根对象开始对象图被序列化.它第一次遇到一个对象时,它在一个表中序列化它,为它生成一个临时ID,并序列化容器类中的ID.如果序列化程序随后遇到相同的对象,它会在表中查找并再次存储运行时ID.
因此,可以序列化多次引用节点的循环对象图和图.
一棵树串行如XmlSerializer较为有限.它从被序列化的根对象开始递归地下降对象图,并在遇到时序列化每个对象.如果它遇到相同的对象两次,它将序列化两次.如果遇到对象图中的循环,它将进入无限递归.那是因为它期望并要求对象层次结构是纯树.
所以,在你的结构中,你有:
public class NodeBase 
{
    public NodeBase Parent { get; private set; }
    public IEnumerable<NodeBase> Children
    {
        get
        {
            return this.children;
        }
    }
}
这两个属性都是公共的,因此可以序列化.因此,根节点将递归序列化其第一个子节点,该Parent属性将递归序列化父节点.
要解决此问题,请标记NodeBase除Childrenas 之外的所有相关属性[XmlIgnore].您还需要使用代理属性将子项显式序列化为数组:
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);
            }
        }
    }
}
这将允许您的树被序列化和反序列化.
(顺便提一下,使类T实现IEqualityComparer<T>非常不典型.通常它实现IEquatable<T>和/或一些单独的比较器类实现IEqualityComparer<T>.)
| 归档时间: | 
 | 
| 查看次数: | 760 次 | 
| 最近记录: |