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)]
(или что-то) для каждого свойства. Тогда нет никаких догадок и нет риска добавления новых членов, которые ломают вещи. Вы можете видеть все, и вы можете понять все.