序列化基础 class 属性
Serializing base class properties
所以,如果我有:
[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,它不起作用。它不知道具体是什么class。我需要添加一个 [ProtoInclude]
。这对我来说很有意义。
我看到的是,如果我序列化 Request 和反序列化 Request,那也不起作用,我认为这是意外的。我希望序列化程序已经知道在这种情况下工作所需的一切。我需要在 BaseRequest 中包含 [ProtoInclude]
,即使我正在序列化的只是 Request。
我 运行 遇到麻烦的地方是我在库中定义了一个 BaseRequest,而该库的使用者需要继承它。基本上,一种特定类型的请求必须附加数据——除了将继承和 copy/pasting 代码转储到每个子 class 之外,是否有这种模式?
我想出了一个办法,我认为它会奏效,尽管确实感觉应该有更好的方法:
[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; }
}
为了让您序列化 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
{
[ProtoMember(1)] public Guid Guid { get; set; }
}
[ProtoContract]
public class Request : BaseRequest
{
[ProtoMember(1)] public long Id { get; set; }
}
我尝试序列化 Request 和反序列化 BaseRequest,它不起作用。它不知道具体是什么class。我需要添加一个 [ProtoInclude]
。这对我来说很有意义。
我看到的是,如果我序列化 Request 和反序列化 Request,那也不起作用,我认为这是意外的。我希望序列化程序已经知道在这种情况下工作所需的一切。我需要在 BaseRequest 中包含 [ProtoInclude]
,即使我正在序列化的只是 Request。
我 运行 遇到麻烦的地方是我在库中定义了一个 BaseRequest,而该库的使用者需要继承它。基本上,一种特定类型的请求必须附加数据——除了将继承和 copy/pasting 代码转储到每个子 class 之外,是否有这种模式?
我想出了一个办法,我认为它会奏效,尽管确实感觉应该有更好的方法:
[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; }
}
为了让您序列化 Request 和反序列化 BaseRequest 等,它通过从 最基本类型 开始并向更多派生类型工作来实现继承;所以如果这是 xml,它将是:
<BaseType>
<BaseTypeField1/>
//...
<--- at most one, possibly none, of the following -- >
<SubType1>...</SubType1>
<SubType2>...</SubType2>
</BaseType>
它需要在第一次尝试接触继承模型中的任何类型时建立对 BaseType 的这种理解。现在,发现您的基类型很容易,但是通过反射发现任何类型的每个可能的派生类型 真的很难 ,因此 ProtoInclude 需要在基类型上,而不是派生类型上。
如果您可以提供可靠、一致的字段编号到子类型的映射,则可以在运行时 而不是 通过 ProtoInclude 配置它,但是:您需要提供并管理您自己的子类型注册表。如果你有这个,我可以告诉你如何更好地配置模型。