c# - 如何让protobuf-net和protostuff相互支持.Net和Java中的继承类?

标签 c# java protobuf-net protostuff

我正在 Windows 系统上基于 .Net 的程序与 Android 设备之间进行通信。在 .Net 端,我使用 Marc Gravell 的优秀 protobuf-net 程序,在 Android 端,我使用 David Yu 的优秀 protostuff 程序。

我的过程(到目前为止)是使用 .Net 类作为定义类。我使用 protobuf-net Serializer.GetProto() 方法生成 .proto 文件,并使用 protostuff 的 protostuff 编译器程序生成或多或少与 .Net 类相对应的 Java 类。

这似乎工作得相当好,只是我遇到了继承问题。是的,我知道,继承不应该与 Protocol Buffer 一起使用。但 protobuf-net 和 protostuff 都以自己的方式实现了对继承类的支持。

所以我的问题是,是否有人建议一种简单的方法来将继承的 C# 类映射到继承的 Java 类,反之亦然?

这是我正在使用的示例。这些是 C# 类:

   public /* abstract */ class ProgramInfoBase
   {
      private string _programName;

      private string _programVersion;

      [ProtoMember(1)]
      public string ProgramName
      {
         get { return _programName; }
         set { _programName = value; }
      }

      [ProtoMember(2)]
      public string ProgramVersion
      {
         get { return _programVersion; }
         set { _programVersion = value; }
      }
   }


   public class ProgramInfoAndroid : ProgramInfoBase
   {
      private string _androidDeviceName;


      [ProtoMember(1)]
      public string AndroidDeviceName
      {
         get { return _androidDeviceName; }
         set { _androidDeviceName = value; }
      }
   }


   public class ProgramInfoWindows : ProgramInfoBase
   {
      private string _windowsMachineName;

      [ProtoMember(1)]
      public string WindowsMachineName
      {
         get { return _windowsMachineName; }
         set { _windowsMachineName = value; }
      }
   }

这是我的 .proto 文件之一:

package Merlinia.MessagingDefinitions;

option java_package = "com.Merlinia.MMessaging_Test.protostuff";

message ProgramInfoAndroid {
   optional string AndroidDeviceName = 1;
}
message ProgramInfoBase {
   optional string ProgramName = 1;
   optional string ProgramVersion = 2;
   // the following represent sub-types; at most 1 should have a value
   optional ProgramInfoAndroid ProgramInfoAndroid = 1001;
   optional ProgramInfoWindows ProgramInfoWindows = 1002;
}
message ProgramInfoWindows {
   optional string WindowsMachineName = 1;
}

通过 protostuff 的 protostuff-compiler 程序运行该程序会生成三个独立的 Java 类,这是可以预料的。但我想让它为Java类生成相应的C#类继承,以及protobuf-net和protostuff之间的序列化和反序列化,以支持两端的继承类。

编辑:

我现在改变主意了。请参阅以下问题:How to get protobuf-net to flatten and unflatten inherited classes in .Net?

最佳答案

首先,注意protobuf规范中并没有定义多态性;任何实现都是定制的。不过,如果它们是一样的就好了。

基本上,看起来他们采用了根本不同的范式; protobuf-net 将子类型视为从基本类型向下开始的嵌套对象,根据您发布的 .proto (由于熟悉的注释,我假设它来自 GetProto)。做出这一选择的原因有很多,包括:

  • 数据可以通过没有任何继承概念的实现进行建模和解析
  • 数据中没有类型/名称/元/等依赖关系(这是 protobuf 在其他地方避免的,所以保留这一点很好)
  • 这还有助于提供平台之间的完全可移植性
  • 数据在类型重构后仍然存在
  • 如果读取器/写入器应用程序处于不同级别,则客户端仍然可以读取它确实知道的数据,即使写入器添加了它不知道的新子类你知道
  • 适用于任意字段、合并等(只要两个合并不在不同的继承分支中)

然而,protostuff 却以不同的方式做事;浏览一下存储库,它将类型名称写入字段 127(并将数据字段限制为 126),并使用该名称执行类型解析。我猜测(未经测试)这意味着在.proto术语中架构是:

message ProgramInfoBase {
   optional string ProgramName = 1;
   optional string ProgramVersion = 2;
   required string MagicTypeName = 127;
}
message ProgramInfoWindows {
   optional string ProgramName = 1;
   optional string ProgramVersion = 2;
   optional string WindowsMachineName = 3;
   required string MagicTypeName = 127;
}
message ProgramInfoAndroid {
   optional string ProgramName = 1;
   optional string ProgramVersion = 2;
   optional string AndroidDeviceName = 3;
   required string MagicTypeName = 127;
}

所以,此时您有几个选择:

  • 以完全不使用继承的方式重新建模这两种实现中的数据 - 这样您就拥有了一个平面 DTO 模型;您当然可以选择在反序列化后将其恢复为分层域模型
  • 选择一个模型(大概是您已经有数据的模型),并继续在该实现中使用继承,并在另一侧将该实现建模为 DTO

例如,如果您将 java 代码保持为多态,.NET 代码将需要类似上面的带有魔术类型名称的内容,但是:这将变得真的 存在冲突的困惑 - 例如,如果字段 1 在一个子类型中是 int Foo,而在另一个子类型中是 string Bar:不好的事情;您还需要硬编码/识别 pojo 类型名称。我不想自吹自擂,这些正是我在 protobuf-net 实现中努力规避的问题、冲突和名称依赖类型

如果您将 protobuf-net 保持为多态,那么您大概可以从您发布的 .proto 开始,然后检查(在 java 端反序列化之后)ProgramInfoAndroid 或 ProgramInfoWindows 是否为非空;然后根据哪个非空,将其映射到 3 种不同的域类型之一。

关于c# - 如何让protobuf-net和protostuff相互支持.Net和Java中的继承类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18565057/

相关文章:

c# - 如何在使用 c# protobuf-net 序列化时将对象附加到文件?

serialization - protobuf-net 和使用接口(interface)序列化链表

c# - 如何强制 AutoFixture 创建 ImmutableList

java - 如何在 Eclipse 中运行单个测试包及其子包?

Java 运行时执行 SQL 脚本在 SQL 错误时继续

Java 应用程序(带有 GUI)即服务

c# - 如何使用 protobuf-net 进行 xml 序列化?

c# - 使用 C# 的 GnuPG 包装器

c# - 使用 AutoMapper 的默认映射

c# - .net 核心应用程序目标 Linux 上的 .net framework 4.5.2