protobuf-net: Wykryto możliwą rekursję
Otrzymuję wyjątek próbujący serializować wykres obiektu (niezbyt głęboki). Znacząca część tego jest taka:
[BŁĄD] FATAL NIEZWYKŁY WYJĄTEK: PrototoBuf.ProtoException: Możliwa rekursja d etched (przesunięcie: 5 poziom (y)): czerwony w ProtoBuf.ProtoWriter.CheckRecursionStackAndPush (obiekt) <0x00127> w ProtoBuf.ProtoWriter.StartSubItem (obiekt, ProtoBuf.ProtoWriter.StartSubItem (obiekt, ProtoBuf.ProtoWriter. , bool) <0x0002f>
Wykres przedstawia strukturę pliku / katalogu, a mój model (uproszczony) wygląda tak:
<code>[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; } } </code>
Głębokość tego drzewa jest blisko 10-15 poziomów, które są mniejsze niżProtoBuf.ProtoWriter.RecursionCheckDepth
wartość (25). (Więc może to jest błąd?)wersja protobuf-net używany jest zestawiony z pniav2 (rev 491).
Właściwie to rozwiązałem go modyfikując kod protobuf-net. Zmieniłem wartośćProtoBuf.ProtoWriter.RecursionCheckDepth
do 100 i wszystko wydaje się być w porządku.
Pytanie brzmi, czy istnieje jakiś „prawdziwy” sposób na serializację takiego rodzaju wykresu bez modyfikacji kodu protobuf? Czy takie zachowanie jest poprawne, czy jest to błąd?
Moja platforma jestMono-2.10-8 w systemie Windows 7 Professional 64-bit
P.S. Odkryłem również, że jeśli deserizlie z następującym kodem, powinienem mieć konstruktor bez parametrów PackageDirectory, aby był publiczny.
<code>var value = new PackageDirectory(); RuntimeTypeModel.Default.Deserialize(ms, value, typeof(PackageDirectory), new SerializationContext { Context = new DeserializationContext { FileStream = _file, }}); </code>
To kolejny temat, ale jest dobrze zilustrowany przedstawionym kodem. Myślę, że w tym przypadku deklarowanie prywatnego konstruktora powinno być dozwolone, ponieważ teraz zachowanie różni się od tego dla Serializer.Deserialize (...).