Сериализация свойств базового класса

Итак, если у меня есть:

        [ProtoContract]
  public abstract class BaseRequest
  {
     [ProtoMember(1)] public Guid Guid { get; set; }
  }

  [ProtoContract]
  public class Request : BaseRequest
  {
     [ProtoMember(1)] public long Id { get; set; }
  }

и я пытаюсь сериализовать Request и десериализовать BaseRequest, это не сработает. Он не знает, что такое конкретный класс. Мне нужно было бы добавить. Это имеет смысл для меня.

Я вижу, что если я сериализую Request и десериализую Request, это тоже не сработает, что я считаю неожиданным. Я ожидаю, что сериализатор уже знает все, что ему нужно для работы в этом случае. Мне нужно включить [ProtoInclude] на BaseRequest, даже если все, что я сериализую, - это Request.

Проблема заключается в том, что у меня есть BaseRequest, определенный в библиотеке, и потребители этой библиотеки должны наследовать от нее. По сути, к конкретному запросу должны быть прикреплены данные - есть ли для этого шаблон, помимо сброса наследования и копирования / вставки этого кода в каждый дочерний класс?

2 ответа

Чтобы позволить вам сериализовать Request и десериализовать BaseRequest и т. Д., Он реализует наследование, начиная с самого базового типа и работая над более производными типами; поэтому, если бы это был xml, это было бы:

      <BaseType>
    <BaseTypeField1/>
    //...
    <--- at most one, possibly none, of the following -- >
    <SubType1>...</SubType1>
    <SubType2>...</SubType2>
</BaseType>

И ему необходимо сформировать это понимание BaseType в первый раз, когда он пытается коснуться любого из типов в модели наследования . Теперь обнаружить свой базовый тип легко, но обнаружить каждый возможный производный тип любого типа с помощью отражения действительно сложно , поэтому ProtoInclude должен быть на базовых типах, а не на производных типах.


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

Я придумал, как это сделать, и думаю, что это сработает, хотя, безусловно, кажется, что должен быть способ получше:

      [ProtoContract]
public abstract class BaseRequest
{
   public static int NextSubType = 1000;
   public static ConcurrentDictionary<Type, int> Initialized = new ConcurrentDictionary<Type, int>();
   public static object SyncObject = new object();
 
   [ProtoMember(1)] public Guid Guid { get; set; }

   protected BaseRequest()
   {
      var type = this.GetType();

      if (!Initialized.ContainsKey(type))
      {
         lock (SyncObject)
         {
            if (!Initialized.ContainsKey(type))
            {
               var next = Interlocked.Increment(ref BaseRequest2.NextSubType);
               RuntimeTypeModel.Default.Add(typeof(BaseRequest2), true).AddSubType(next, type);
               Initialized[type] = next;
            }
         }
      }
   }
}

[ProtoContract]
public class Request : BaseRequest
{
   [ProtoMember(1)] public long Id { get; set; }
}
Другие вопросы по тегам