Protobuf .NET сериализация для классов наследования

Я пытаюсь перенести сериализатор кода из 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, использующим имя для автоматического назначения Order.

1 ответ

Решение

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

Да, это так.

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

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

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

Именно так.

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

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

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

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

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

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

Другие вопросы по тегам