2012-04-09 66 views
4

我得到一個異常,試圖序列化對象圖(不是很深)。它有意義的部分是這樣的:protobuf-net:檢測到可能的遞歸

[ERROR]致命未處理的異常:ProtoBuf.ProtoException:可能 遞歸d etected(偏移量:5級(S)):紅色在 ProtoBuf.ProtoWriter.CheckRecursionStackAndPush(對象)< 0x00127>在 ProtoBuf.ProtoWriter.StartSubItem(對象,ProtoBuf.ProtoWriter,布爾) < 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網使用是一個編譯從中繼v2轉491)。

其實,我解決了它與修改protobuf網絡代碼。我將ProtoBuf.ProtoWriter.RecursionCheckDepth的值更改爲100,一切似乎都沒問題。

問題是如果有任何「真正」的方式來序列化這種類型的圖,而不修改protobuf代碼?這樣的行爲是正確的還是錯誤?

我的平臺是單-2.10-8在Windows 7專業版64位

附:我還發現,如果我deserizlie與thw下面的代碼,我應該有PackageDirectory無參數構造函數公開。

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

這是另一個話題,但它提供的代碼很好地說明。我認爲在這種情況下應該允許聲明私有構造函數,因爲現在行爲與Serializer.Deserialize(...)的行爲不同。

+0

該構造函數的問題聽起來很奇怪和意外 - 再次,將需要repro;這個運行的平臺是什麼?正規的.NET?要麼...?(由於平臺的限制,SL和CF在這裏有一些細微的差別) – 2012-04-09 09:03:22

+0

@MarcGravell,對不完整的信息抱歉,我忘了指定我的平臺。它是單聲道的。我會編輯一個問題。 – ILya 2012-04-09 15:51:09

+0

單聲道...? Linux呢? iOS版?另外:您使用的是哪個**確切的**版本號? – 2012-04-09 17:23:23

回答

6

此異常僅當相同的參考中的數據看出(在同一路徑兩次)時引發和跟蹤是纔會啓用當深度爲至少RecursionCheckDepth。這立即讓我懷疑引用的10-15深度限制,雖然protobuf處理相當於的情況不一定與您計算的相同。對我來說,將這個數字提高到100是沒有意義的,事實上,這個RecursionCheckDepth的存在純粹是一種優化,用於限制「典型」圖形中涉及的工作量,只有在這種情況下才能進行更嚴格的檢查開始看起來很深。

但是,我注意到這可能也暗示了基於繼承的處理中的一些細微的錯誤,也許也與AsReference有關。我廣泛而持續地使用protobuf-net,並且我沒有看到這樣的問題。如果你有一個可複製的repro,我非常想看到它。

+0

感謝您的回覆!改變RecursionCheckDepth只是一個臨時解決方案,讓我可以進一步移動我的項目,所以這不是一個真正的選擇......我將準備明天再現的錯誤示例,並將它分享到某處。 – ILya 2012-04-09 15:56:55

+0

你實際上試圖檢測*週期*,對嗎?遞歸看起來完全正常,但如果深度足夠,它也可能是有害的。 (鏈接列表任何人?) – 2012-04-09 18:09:13

+0

@BenVoigt是的,這是週期是這裏的問題(因爲這是一個基於樹的序列化程序,有限的可選參考跟蹤支持) – 2012-04-09 18:17:43