简体   繁体   English

序列化基础 class 属性

[英]Serializing base class properties

So, if I have:所以,如果我有:

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

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

and I try to serialize Request and deserialize BaseRequest, it won't work.我尝试序列化Request并反序列化BaseRequest,它不起作用。 It doesn't know what is the concrete class.它不知道具体的 class 是什么。 I would need to add a [ProtoInclude] .我需要添加一个[ProtoInclude] That makes sense to me.这对我来说很有意义。

What I'm seeing is that if I serialize Request and deserialize Request, that also doesn't work, which I think is unexpected.我看到的是,如果我序列化请求并反序列化请求,那也不起作用,我认为这是出乎意料的。 I would expect the serializer to already know everything it needs in order to work in that case.我希望序列化程序已经知道在这种情况下工作所需的一切。 I need to include the [ProtoInclude] on BaseRequest even if all I'm serializing is Request.即使我正在序列化的只是请求,我也需要在 BaseRequest 中包含[ProtoInclude]

Where I run into trouble is that I have a BaseRequest defined in a library and consumers of that library need to inherit from it.我遇到麻烦的地方是我在库中定义了一个 BaseRequest 并且该库的使用者需要从它继承。 Basically, a particular kind of request has to have data attached to it-- is there a pattern for this, outside of dumping the inheritance and copy/pasting that code into every child class?基本上,一种特定类型的请求必须附加数据——除了转储 inheritance 并将该代码复制/粘贴到每个子 class 之外,是否有这种模式?

In order to allow you to serialize Request and deserialize BaseRequest, etc, it implements inheritance by starting at the most base type and working out towards more derived types;为了让你可以序列化Request和反序列化BaseRequest等,它实现了inheritance,从最基础的类型开始,向更多的派生类型发展; so if this was xml, it would be:所以如果这是 xml,它将是:

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

And it needs to build this understanding of BaseType the first time it tries to touch any of the types in the inheritance model .并且它需要在第一次尝试触及 inheritance model 中的任何类型时建立对 BaseType 的理解。 Now, discovering your base type is easy, but discovering every possible derived type of any type is really hard via reflection, hence why ProtoInclude needs to be on the base types, not the derived types.现在,发现你的基类型很容易,但是通过反射发现任何类型的每个可能的派生类型真的很困难,因此为什么 ProtoInclude 需要在基类型上,而不是派生类型上。


If you can provide a reliable, consistent map of field numbers to subtypes, it can all be configured at runtime instead of via ProtoInclude, but: you'd need to provide and manage your own registry of sub-types.如果您可以为子类型提供可靠、一致的字段编号 map,则可以在运行时而不是通过 ProtoInclude 进行配置,但是:您需要提供和管理自己的子类型注册表。 If you have this, I can show you how to configure the model in better ways.如果你有这个,我可以向你展示如何以更好的方式配置 model。

I figured out a way to do it, and I think it'll work, although it certainly feels like there ought to be a better way:我想出了一种方法,我认为它会起作用,尽管感觉应该有更好的方法:

[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; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM