我在尝试序列化对象图时遇到异常(不是很深)。其中有意义的部分是这样的:
[错误] 致命的未处理异常:ProtoBuf.ProtoException:检测到可能的递归(偏移量:5 级):ProtoBuf.ProtoWriter.CheckRecursionStackAndPush(对象)<0x00127> 在 ProtoBuf.ProtoWriter.StartSubItem(对象,ProtoBuf.ProtoWriter ,bool) <0x0002f>
该图表示文件/目录结构,我的模型(简化)如下所示:
[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 版本是从trunk v2(rev 491)编译的版本。
实际上,我通过修改 protobuf-net 代码解决了这个问题。我将值更改ProtoBuf.ProtoWriter.RecursionCheckDepth
为 100,一切似乎都很好。
问题是是否有任何“真正的”方法可以在不修改 protobuf 代码的情况下序列化此类图形?这种行为是正确的还是错误的?
我的平台是Windows 7 Professional 64 位上的 Mono-2.10-8
PS 另外我发现,如果我使用以下代码进行解串,我应该将 PackageDirectory 无参数构造函数公开。
var value = new PackageDirectory();
RuntimeTypeModel.Default.Deserialize(ms, value, typeof(PackageDirectory), new SerializationContext {
Context = new DeserializationContext {
FileStream = _file,
}});
这是另一个主题,但已通过提供的代码很好地说明了这一点。我认为在这种情况下应该允许声明私有构造函数,因为现在行为与 Serializer.Deserialize(...) 的行为不同。