我有一个名为ConfigNode
的树结构类(类似于SerializationInfo
),它可以将配置值存储在列表中并控制子节点。当我添加IEnumerable<ConfigNode>
作为派生的接口时,protobuf-net在序列化期间失败并导致StackOverFlowException,即使IgnoreListHandling标志设置为true。
[Serializable, DataContract, ProtoContract(IgnoreListHandling = true)]
public class ConfigNode : Entity, ICloneable, INotifyPropertyChanged
{
[DataMember, ProtoMember(1)]
private Dictionary<String, PrimitiveSurrogate> values = new Dictionary<String, PrimitiveSurrogate>();
private Dictionary<String, ConfigNode> _Childs = new Dictionary<String, ConfigNode>();
[DataMember, ProtoMember(2)]
public Dictionary<String, ConfigNode> Childs
{
get
{
return _Childs;
}
private set
{
_Childs = value;
}
}
[DataMember, ProtoMember(3)]
public ConfigNode Parent { get; set; }
}
工作正常。 PrimitiveSurrogate是一个结构,存储所有常用的“几乎原语”的字符,如String,Guid,DataTime,float / double,bool,char等。配置值本身将添加到“Store”方法中,这是没有的重要性。它将一个对象作为参数,并尝试将该类型转换为其中一个可存储的数据类型,并将其存储为强类型的PrimitiveSurrogate。实体基类只提供一个Name-property,而不是其他任何东西。
但是只要我将IEnumerable<ConfigNode>
添加到接口列表并添加适当的方法(见下文),任何序列化尝试都会抛出StackOverflowException。
public void Add(ConfigNode child)
{
if (child == null)
throw new ArgumentNullException("child");
if (child.Name == null)
throw new ArgumentException("The child's name was null. The child cannot be added.");
child.Parent = this;
lock (this.Childs)
{
this.Childs[child.Name] = child;
}
}
public IEnumerator<ConfigNode> GetEnumerator()
{
lock (this.Childs)
{
return this.Childs.Values.Clone().GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
lock (this.Childs)
{
return this.Childs.Values.Clone().GetEnumerator();
}
}
“克隆”是一种扩展方法,如下所示:
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection)
{
return collection.ToList();
}
似乎protobuf-net忽略了IgnoreListHandling-flag,有人可以帮忙吗?
答案 0 :(得分:0)
没关系,我发现了错误。在一些更改后,我在Childs-Property和Childs.get()中引入了一个锁,我锁定了属性本身而不是后备字段。由于Monitor-Class试图访问该属性并导致再次访问get-Accessor,因此导致StackOverflow。
现在(de)顺利序列化。
修正版:
[DataMember, ProtoMember(2)]
public Dictionary<String, ConfigNode> Childs
{
get
{
lock (_Childs)
{
return _Childs;
}
}
private set
{
lock (_Childs)
{
_Childs = value;
}
}
}