Protobuf .NET сериализация для классов наследования - PullRequest
0 голосов
/ 29 июня 2018

Я пытаюсь перенести сериализатор кода из NetDataContract в Protobuf.Net.

Давайте рассмотрим следующий пример класса, чтобы помочь пониманию:

[DataContract(Name "a", IsReference = true)]
class Test
{
    [DataMember(Name = "a")]
    public int Id { get; set; }

    [DataMember(Name = "b")]
    public string Name { get; set; }
}

Чтобы использовать Protobuf .NET с использованием DataContract, я использую следующие опции:

RuntimeTypeModel.Default.InferTagFromNameDefault = true;            
RuntimeTypeModel.Default.AutoAddProtoContractTypesOnly = false;

Используя эти опции, сериализация показанного выше примера работает, но при добавлении наследования его сложность возрастает. Давайте улучшим наш пример с этим классом:

[DataContract(Name = "b", IsReference = true)]
class InheritanceTest : Test
{
    [DataMember(Name = "c")]
    public string Text { get; set; }
}

Теперь, чтобы иметь возможность сериализовать класс "InheritanceTest", который наследуется от "Test", я должен добавить параметр ProtoInclude (уже пытался использовать только KnownType, но он не работал). Атрибуты класса «Тест» должны быть такими:

[DataContract(Name "a", IsReference = true)]
[KnownType(typeof(InheritanceTest)]
[ProtoInclude(<TAG>, typeof(InheritanceTest)]
class Test { ... }

Сложность ИМХО заключается в том, что вам нужно заполнить «TAG» номером, который не используется автоматически из автоматически назначенного заказа членов (DataMembers). В этом примере, если я использую TAG = 1, он получает ошибку, потому что свойство Id уже использует его. То же самое с TAG = 2 и именем свойства. Поэтому мне нужно поставить как минимум 3.

Это нормально, так как этот класс слишком прост, но что мне делать, если у класса есть несколько свойств? И должен ли я менять тег при добавлении к нему свойства? Кажется ужасным для обслуживания.

Как я могу сделать это проще? Я что-то упустил?

Учитывая, что он назначается автоматически, его следует выполнить только один раз и кэшировать. Еще лучше, это должно быть сделано во время компиляции.

Дополнительно ... почему я не могу использовать атрибут [KnownType], и ​​сериализатор автоматически назначает TAG на основе имени DataContract определенного класса? Обратите внимание, что нечто подобное происходит с DataMember, использующим имя для автоматического назначения заказа.

1 Ответ

0 голосов
/ 29 июня 2018

но при добавлении его наследования сложность возрастает.

Да, это так.

И должен ли я менять тег при добавлении к нему свойства?

Вы не должны никогда изменять тег. Когда-либо.

Кажется ужасным для обслуживания.

Точно.

Учитывая, что он назначается автоматически, его следует выполнить только один раз и кэшировать.

Это во время выполнения.

Еще лучше, это должно быть сделано во время компиляции.

Ну, я не концентрируюсь на аспектах "логического вывода", но в целом , это постоянное обсуждение, которое я веду с командой компиляторов.

Я что-то упустил?

Я так думаю, да; в частности, вы не должны использовать опции"выводить по имени" на моделях, которые когда-либо будут меняться. Эта опция была добавлена ​​как прагматичный способ просто заставить работать на существующих фиксированных моделях, но она очень хрупкая - и во многих отношениях опасна. должно быть предупреждениями, которые появляются в вашем intellisense по этому поводу, но, честно говоря, рекомендуемый вариант : всегда быть явным. Добавьте [ProtoMember(42)] (или что-то еще) к каждому свойству. Тогда нет никаких догадок и нет риска добавления новых членов, которые ломают вещи. Вы можете видеть все, и вы можете понять все.

...