Десериализация коллекций с помощью protobuf-net - PullRequest
2 голосов
/ 27 ноября 2011

При переключении с BinaryFormatter на protobuf-net я наблюдал разницу при сериализации коллекций.

В приведенном ниже примере кода Deserialize (protobuf-net v2r470) возвращает разные результаты, если массив создается в пределахкласс (street1), чем снаружи (street2).

Разрешено ли сериализовать коллекции, объявленные в объявлении класса?

[ProtoContract]
public class City
{
    [ProtoMember(1)]
    public string[] streets1;

    [ProtoMember(2)]
    public string[] streets2 = new string[2];
}

City city = new City();

// Instantiate and populate streets1
city.streets1 = new string[2];
city.streets1[0] = "streetA";
city.streets1[1] = "streetB";

// Populate streets2. Already instantiated
city.streets2[0] = "streetA";
city.streets2[1] = "streetB";

// Serializing
using (var file = File.Create("city.bin"))
{
    Serializer.Serialize(file, city);
}

// Deserializing
using (var file = File.OpenRead("city.bin"))
{
    City  getCity = Serializer.Deserialize<City>(file);
}

Десериализация загружает в getCity следующее:

getCity.streets1: "streetA", "streetB" (как и ожидалось)

getCity.streets2: null, null, "streetA", "streetB" <--------- Почему ноль? </p>

Возвращено столько нулей, сколько элементов в коллекции.

1 Ответ

3 голосов
/ 27 ноября 2011

Да, но проблема в том, что protobuf-net предполагает (из-за конкатенируемой природы формата protobuf), что он должен расширять (добавлять в) списки / массивы, и ваш инициализатор поля начиная с длины 2.

Здесь есть как минимум 3 исправления:

  • вы можете добавить SkipConstructor = true к ProtoContract, что будет означать, что он не запускает инициализатор поля
  • в ProtoMember есть синтаксис "списки замены", который говорит, что он должен заменять, а не добавлять (я не могу вспомнить фактическую опцию, но она есть)
  • Вы можете добавить обратный вызов перед десериализацией, чтобы очистить поле между конструктором и десериализацией
...