2012-04-09 5 views
4

Ich bekomme eine Ausnahme Serialisierung Objektgraph (nicht sehr tief). Aussagekräftigen Teil davon ist, wie folgt aus:protobuf-net: Mögliche Rekursion erkannt

[ERROR] FATAL Unbehandelte Ausnahme: ProtoBuf.ProtoException: Mögliche Rekursion d etected (offset: 5-Ebene (n)): rot bei ProtoBuf.ProtoWriter.CheckRecursionStackAndPush (object) < 0x00127> bei ProtoBuf.ProtoWriter.StartSubItem (Objekt, ProtoBuf.ProtoWriter, bool) < 0x0002f>

Der graph repräsentiert sieht Datei/Verzeichnisstruktur und mein Modell (vereinfacht) wie folgt aus:

[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; } 
} 

Die Tiefe dieses Baumes ist in der Nähe von 10-15 Ebenen, die weniger als ProtoBuf.ProtoWriter.RecursionCheckDepth Wert (25). (Also vielleicht ist das ein Fehler?) Die Version von Protobuf-Net ist eine kompiliert aus Kofferraum v2 (rev 491).

Eigentlich löste ich es mit der Änderung von Protobuf-net-Code. Ich habe den Wert von ProtoBuf.ProtoWriter.RecursionCheckDepth auf 100 geändert und alles scheint in Ordnung zu sein.

Die Frage ist, ob es irgendwelche "wahre" Art und Weise zu Serialisieren solcher Art von Graphen ohne Änderung der Protobuf-Code? Ist ein solches Verhalten korrekt oder ist es ein Fehler?

Meine Plattform ist Mono-2,10-8 auf Windows 7 Professional 64-Bit-

P. S. Auch ich fand, dass, wenn ich mit thw folgenden Code deserizlie, ich parameterlosen Konstruktor PackageDirectory haben sollte, um öffentlich zu sein.

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

Es ist ein anderes Thema, aber es ist gut dargestellt mit vorgestellten Code. Ich denke, dass in diesem Fall der private Konstruktor deklariert werden sollte, da sich das Verhalten nun von dem für Serializer.Deserialize (...) unterscheidet.

+0

Das Konstruktor-Problem klingt seltsam und unerwartet - wiederum müsste repro; Auf welcher Plattform läuft das? reguläre .NET? oder...?(SL und CF haben hier einige kleine Unterschiede aufgrund von Einschränkungen der Plattform) –

+0

@MarcGravell, Sorry für unvollständige Informationen, ich habe vergessen, meine Plattform anzugeben. Es ist Mono. Ich werde eine Frage bearbeiten. – ILya

+0

mono auf ...? Linux? iOS? Auch: welche ** genaue ** Versionsnummer verwendest du? –

Antwort

6

Diese Ausnahme wird nur ausgelöst, wenn die gleiche Referenz in den Daten zu sehen ist (zweimal in dem gleichen Pfad) und Tracking ist nur aktiviert, wenn die Tiefe mindestens RecursionCheckDepth ist. Das macht mich sofort verdächtig auf die genannte 10-15 Tiefengrenze, obwohl es nicht unbedingt der Fall ist, dass protobuf die Level ganz genauso handhabt wie du zählst. Es macht keinen Sinn für mich, wenn ich diese Zahl auf 100 setze, damit es funktioniert. Tatsächlich ist die bloße Existenz dieser RecursionCheckDepth rein eine Optimierung, um den Aufwand für "typische" Graphen zu begrenzen, was nur die strengere Überprüfung ermöglicht beginnt tief zu schauen.

Ich bin mir jedoch bewusst, dass dies auch einige subtile Fehler in der vererbungsbasierten Behandlung vorschlagen könnte, vielleicht auch im Zusammenhang mit AsReference. Ich benutze Protobuf-Net ausgiebig und ständig, und ich habe ein solches Problem nicht gesehen. Wenn Sie eine reproduzierbare Repro haben, würde ich es sehr gerne sehen.

+0

Danke für Ihre Antwort! Das Ändern von RecursionCheckDepth war nur eine vorübergehende Lösung, um mich weiter mit meinem Projekt zu bewegen, also ist es nicht wirklich eine Option ... Ich werde morgen ein reproduzierbares Beispiel für einen Fehler vorbereiten und es irgendwo teilen. – ILya

+0

Sie versuchen tatsächlich * Zyklen * zu erkennen, oder? Rekursion scheint völlig normal zu sein, obwohl es auch schädlich sein könnte, wenn es tief genug ist. (verknüpfte Liste jemand?) –

+0

@BenVoigt ja, es ist Zyklen, die das Problem sind hier (da dies ist ein Baum-basierten Serialisierer, mit begrenzten optionalen Referenz-Tracking-Unterstützung) –