Сериализация свойств базового класса
Итак, если у меня есть:
[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; }
}