2012-04-09 2 views
4

Я получаю исключение, пытающееся сериализовать график объекта (не очень глубокий). Значимая часть его, как это:protobuf-net: обнаружена возможная рекурсия

[ОШИБКА] ФАТАЛЬНОЕ необработанное исключение: ProtoBuf.ProtoException: Возможная рекурсии д etected (смещение: 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-нетто: одна составлена ​​из ствола v2 (оборотов 491).

На самом деле, я решил его с модификацией кода protobuf-net. Я изменил значение ProtoBuf.ProtoWriter.RecursionCheckDepth на 100, и все, кажется, в порядке.

Вопрос в том, есть ли какой-либо «истинный» способ сериализации такого графика без изменения кода protobuf? Является ли такое поведение правильным или это ошибка?

Моя платформа Mono-2.10-8 на Windows 7 Professional 64-битном

P.S. Также я обнаружил, что если я deserizlie с этим следующим кодом, у меня должен быть конструктор безпараметрического пакета PackageDirectory, который будет общедоступным.

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

Это еще одна тема, но она хорошо иллюстрируется представленным кодом. Я думаю, что в этом случае объявление частного конструктора должно быть разрешено, потому что теперь поведение отличается от одного для Serializer.Deserialize (...).

+0

Проблема с конструктором звучит странно и неожиданно - опять же, потребуется повторить; на какой платформе это работает? регулярный .NET? или...?(SL и CF имеют некоторые незначительные различия здесь, из-за ограничений платформы) –

+0

@MarcGravell, Извините за неполную информацию, я забыл указать свою платформу. Это моно. Я отредактирую вопрос. – ILya

+0

моно на ...? Linux? IOS? Также: какой ** точный ** номер версии вы используете? –

ответ

6

Это исключение только тогда, когда та же ссылка видно в данных (два раза в том же пути), и отслеживание включается только, когда глубина составляет, по меньшей мере RecursionCheckDepth. Что сразу заставляет меня подозрительно относиться к указанному пределу глубины 10-15, хотя это не обязательно так, что protobuf обрабатывает уровни довольно так же, как вы считаете. Для меня не имеет значения, что повышение этого числа до 100 должно заставить его работать - на самом деле само существование этого RecursionCheckDepth - это просто оптимизация для ограничения усилий, связанных с «типичными» графиками, только для более строгой проверки, если это начинает выглядеть глубоко.

Я, однако, помню, что это может также предложить некоторые тонкие ошибки в обработке наследования, возможно, также связанные с AsReference. Я использую protobuf-net экстенсивно и постоянно, и я не видел такой проблемы. Если у вас есть воспроизводимый репродуктор, я бы очень хотел его увидеть.

+0

Спасибо за ваш ответ! Изменение RecursionCheckDepth было лишь временным решением, позволяющим мне двигаться дальше с моим проектом, поэтому это не вариант ... Я подготовлю воспроизводимый пример ошибки завтра и поделится им где-нибудь. – ILya

+0

Вы на самом деле пытаетесь обнаружить * циклы *, правильно? Рекурсия кажется вполне нормальной, хотя она тоже может быть вредной, если достаточно глубоко. (связанный список кто-нибудь?) –

+0

@BenVoigt да, это проблемы, которые здесь возникают (так как это сериализатор на основе дерева, с ограниченной опциональной поддержкой отслеживания ссылок) –

Смежные вопросы