2

所以,如果我有:

  [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,它不起作用。它不知道具体的类是什么。我需要添加一个[ProtoInclude]. 这对我来说很有意义。

我看到的是,如果我序列化请求并反序列化请求,那也不起作用,我认为这是出乎意料的。我希望序列化程序已经知道在这种情况下工作所需的一切。[ProtoInclude]即使我要序列化的只是请求,我也需要包含on BaseRequest。

我遇到麻烦的地方是我在库中定义了一个 BaseRequest 并且该库的使用者需要从它继承。基本上,一种特定类型的请求必须附加数据——除了转储继承并将该代码复制/粘贴到每个子类中之外,是否有这种模式?

4

2 回答 2

1

为了让你可以序列化Request和反序列化BaseRequest等,它通过从最基础的类型开始,向更多的派生类型进行继承来实现;所以如果这是xml,它将是:

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

它需要在第一次尝试接触继承模型中的任何类型时建立对 BaseType 的理解。现在,发现你的基类型很容易,但是通过反射发现任何类型的每个可能的派生类型真的很困难,因此为什么 ProtoInclude 需要在基类型上,而不是派生类型上。


如果您可以提供可靠、一致的字段编号到子类型的映射,则可以在运行时而不是通过 ProtoInclude 进行配置,但是:您需要提供和管理自己的子类型注册表。如果你有这个,我可以向你展示如何以更好的方式配置模型。

于 2021-05-01T07:54:30.693 回答
0

我想出了一种方法,我认为它会起作用,尽管感觉应该有更好的方法:

[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; }
}
于 2021-05-01T03:53:12.407 回答