Как добавить объект в файл при сериализации с помощью с # protobuf-net?

У меня есть исходный код Protobuf-net, который сериализует объект в файл.

var person = new Person {
        Id = 12345, Name = "Fred",
        Address = new Address {
            Line1 = "Flat 1",
            Line2 = "The Meadows"
        }
    };
    using (var file = File.Create("person.bin")) {
        ProtoBuf.Serializer.Serialize(file, person);
    }

Но предположим, что у меня есть два экземпляра Person, которые я хочу сериализовать в один файл. Как я могу это сделать?


person Rezoan    schedule 07.03.2013    source источник
comment
Я получил решение в stackoverflow.com/questions/817641/, спасибо Agin Марку Гравеллу   -  person Rezoan    schedule 07.03.2013


Ответы (1)


protobuf, в чистом смысле слова, не имеет никакого «ограничителя», кроме конца файла (это делается для того, чтобы объекты можно было объединять / объединять просто путем конкатенации блобов).

Однако мы можем внедрить свои собственные маркеры, например, добавив к каждому объекту префикса длины следующих за ним данных.

protobuf-net завершает это, предоставляя SerializeWithLengthPrefix метод. Существуют различные методы десериализации из этого, но самый простой - это DeserializeItems, который по очереди дает вам потоковую последовательность объектов (ленивая буферизация из потока в итераторе - поэтому он идеально подходит для очень больших последовательностей).

Для информации, чтобы вы могли увидеть, как это реализовано: если вы используете PrefixStyle.Base128 и положительное значение fieldNumber, то на проводе это выглядит так же, как если бы у вас был объект-оболочка, например:

[ProtoContract]
public class DoesNotExist {
    [ProtoMember({fieldNumber})]
    public List<Person> People {get;set;}
}

основные отличия заключаются в том, что фактического DoesNotExist типа / экземпляра не существует и List<T> не создается - вы просто получаете Person экземпляры.

person Marc Gravell    schedule 07.03.2013
comment
Марк, пожалуйста, ответьте, на что влияет номер поля (последний аргумент) (значение = 0) в Serializer.SerializeWithLengthPrefix (s, command1, PrefixStyle.Base128, 0); - person Rezoan; 07.03.2013
comment
@Rezoan в основном применяется при использовании префикса Base128; если указано положительное число, то префикс записывается таким образом, чтобы весь составной поток сам стал допустимым потоком protobuf, как в примере DoesNotExist. Одно интересное использование этого состоит в том, что он позволяет вам записывать разнородные объекты в один и тот же поток и снимать их последовательно, то есть вы можете написать Person, Order, Person, Person, а затем Address. Вам нужно будет использовать неуниверсальный API и преобразователь типов, чтобы убрать их из потока, но это действительно удобно для ... - person Marc Gravell; 07.03.2013
comment
@Rezoan ... такие вещи, как сокеты на основе сообщений или RPC; у каждой операции может быть свой номер поля, который вы обрабатываете отдельно. Лично мне всегда нравится включать номер поля только потому, что мне нравится, чтобы весь поток был действительным protobuf - person Marc Gravell; 07.03.2013
comment
Благодарю. Я очень скоро вернусь к вам с другой проблемой. = D - person Rezoan; 07.03.2013
comment
Чтобы быть ясным, я задаю вопрос @Marc. если я сериализую этот объект человека с помощью c # protbuf-net в файл. легко ли можно десериализовать с помощью буфера протокола Google c ++? - person Rezoan; 07.03.2013
comment
@ Резоан к; это более интересный вопрос :) Ответ, в конечном счете, положительный, но: вам, возможно, придется обрабатывать чтение префиксов длины вручную. В качестве альтернативы, если вы сообщите C ++ о DoesNotExist, вы можете писать (на C #) через SerializeWithLengthPrefix, но десериализовать в C ++, попросив его десериализовать DoesNotExist - имеет ли это смысл? - person Marc Gravell; 07.03.2013
comment
да, мне нужно обрабатывать префикс длины вручную. У меня есть задача, которая должна сериализовать несколько структур в один файл с помощью протобуфера Google, и снова этот файл необходимо десериализовать. Часть сериализации должна быть написана на C #, а часть десериализации должна быть на C ++. вот почему я задаю вам этот вопрос. - person Rezoan; 07.03.2013