protobuf-net:检测到可能的递归 [英] protobuf-net: Possible recursion detected

查看:57
本文介绍了protobuf-net:检测到可能的递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到异常,试图序列化对象图(不是很深).有意义的部分是这样的:

I get an exception trying to serialize object graph (not very deep). Meaningful part of it is like this:

[错误]致命异常例外:ProtoBuf.ProtoException:可能递归方向(偏移:5级):红色为ProtoBuf.ProtoWriter.CheckRecursionStackAndPush(对象)< 0x00127>在ProtoBuf.ProtoWriter.StartSubItem(对象,ProtoBuf.ProtoWriter,布尔)< 0x0002f>

[ERROR] FATAL UNHANDLED EXCEPTION: ProtoBuf.ProtoException: Possible recursion d etected (offset: 5 level(s)): red at ProtoBuf.ProtoWriter.CheckRecursionStackAndPush (object) <0x00127> at ProtoBuf.ProtoWriter.StartSubItem (object,ProtoBuf.ProtoWriter,bool) <0x0002f>

该图表示文件/目录结构,而我的模型(简化)如下所示:

The graph represents file/directory structure and my model (simplified) looks like this:

[ProtoContract] 
[ProtoInclude(100, typeof(PackageDirectory))]
[ProtoInclude(200, typeof(PackageFile))]
public abstract class PackageMember
{
   [ProtoMember(1)] 
   public virtual string Name { get; protected set; }

   [ProtoMember(2, AsReference=true)] 
   public PackageDirectory ParentDirectory { get; protected set; }  
}

[ProtoContract]
public class PackageDirectory : PackageMember
{
   [ProtoMember(3)]
   private Dictionary<string, PackageMember> _children;

   public PackageDirectory()
   {
      _children = new Dictionary<string, PackageMember>();
   }

   public PackageDirectory (string name, PackageDirectory parentDirectory)
      : this()
   {
      this.ParentDirectory = parentDirectory;
      this.Name = name;         
   }

   public void Add (PackageMember member)
   {
      _children.Add(member.Name, member);
   }
}

[ProtoContract]
public class PackageFile : PackageMember
{
   private Stream _file;
   private BinaryReader _reader;

   private PackageFile() 
   {}

   public PackageFile (string name, int offset, int length, PackageDirectory directory,  Stream file)
   {
      this.Name = name;
      this.Length = length;
      this.Offset = offset;
      this.ParentDirectory = directory;

      _file = file;
      _reader = new BinaryReader(_file);
   }

   [OnDeserialized]
   protected virtual void OnDeserialized(SerializationContext context)
   {
      var deserializationContext = context.Context as DeserializationContext;

      if (deserializationContext != null)
      { 
         _file = deserializationContext.FileStream;
         _reader = new BinaryReader(_file);
      }
   }

   [ProtoMember(3)]
   public int Offset { get; private set; }

   [ProtoMember(4)]
   public int Length { get; private set; }
}

这棵树的深度接近10-15级,小于 ProtoBuf.ProtoWriter.RecursionCheckDepth 值(25).(所以也许这是一个错误?)使用的 protobuf-net版本是从主干 v2 ( rev 491 )编译的版本.

The depth of this tree is near 10-15 levels, which less than ProtoBuf.ProtoWriter.RecursionCheckDepth value (25). (So maybe this is a bug?) The version of protobuf-net used is one compiled from trunk v2 (rev 491).

实际上,我通过修改protobuf-net代码解决了它.我将 ProtoBuf.ProtoWriter.RecursionCheckDepth 的值更改为100,一切似乎都正常.

Actually, i solved it with modification of protobuf-net code. I changed value of ProtoBuf.ProtoWriter.RecursionCheckDepth to 100 and everything seems to be ok.

问题是在不修改protobuf代码的情况下,是否有任何真"方法来序列化这种图形?这样的行为是正确的还是错误?

The question is if there any "true" way to serialize such kind of graph without modification of protobuf code? Is such a behavior correct or it's a bug?

我的平台是Windows 7 Professional 64位上的 Mono-2.10-8

My platform is Mono-2.10-8 on Windows 7 Professional 64-bit

P.S.我还发现,如果我用下面的代码进行反序列化,则应该让PackageDirectory无参数构造函数公开.

P.S. Also i found that if i deserizlie with thw following code, i should have PackageDirectory parameterless constructor to be public.

var value = new PackageDirectory();
RuntimeTypeModel.Default.Deserialize(ms, value, typeof(PackageDirectory), new SerializationContext {
   Context = new DeserializationContext {
   FileStream = _file,
}});

这是另一个主题,但是所提供的代码对此进行了很好的说明.我认为在这种情况下应该允许声明私有构造函数,因为现在行为不同于Serializer.Deserialize(...).

It's another topic but it's well illustrated with presented code. I think that in this case declaring private constructor should be allowed because now the behavior differs from one for Serializer.Deserialize(...).

推荐答案

仅当在数据中看到相同的引用时(在同一路径中两次),才会引发此异常.em>仅在深度至少为 RecursionCheckDepth 时启用.这让我立即怀疑所引用的10-15深度限制,尽管protobuf处理与您计数相同的相当级别的情况并不一定.对我来说,将这个数字提高到100应该可以使它起作用-实际上,这个 RecursionCheckDepth 的存在纯粹是为了限制典型"图形中的工作而进行的优化.启用更严格的检查,以使其看起来更深.

This exception is thrown only when the same reference is seen in the data (twice in the same path), and tracking is only enabled when the depth is at least RecursionCheckDepth. Which immediately makes me suspicious of the 10-15 depth limit cited, although it is not necessarily the case that protobuf handles levels quite the same as you are counting. It does not make sense to me that raising this number to 100 should make it work - in fact, the very existence of this RecursionCheckDepth is purely an optimisation to limit the effort involved in "typical" graphs, only enabling the more rigorous checking if it starts to look deep.

但是,我谨记这可能还会暗示基于继承的处理中的一些细微错误,也许还与 AsReference 有关.我广泛而不断地使用protobuf-net,但还没有看到这样的问题.如果您有可复制的复制品,我非常希望看到它.

I am, however, mindful that this might also suggest some subtle bug in inheritance-based handling, perhaps also related to AsReference. I use protobuf-net extensively and constantly, and I haven't seen such an issue. If you have a reproducible repro I would very much like to see it.

这篇关于protobuf-net:检测到可能的递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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