2

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

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

这似乎工作得很好,除了我遇到了继承问题。是的,我知道,继承不应该与协议缓冲区一起使用。但是 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之间的序列化和反序列化,以支持两端的继承类。

编辑:

我现在改变主意了。请参阅以下问题:如何让 protobuf-net 在 .Net 中展平和取消展平继承的类?

4

1 回答 1

3

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

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

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

然而,protostuff 以不同的方式做事。查看 repo,它将类型名称写入字段 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 代码将需要类似于上面的带有魔术类型名称的东西,但是:如果存在冲突,这将变得非常混乱 - 例如,如果字段 1int Foo在一个子中-type,string Bar在另一个子类型中:坏事;您还需要硬编码/识别 pojo 类型名称。不想吹我自己的小号,这些正是我在 protobuf-net 实现中努力规避的问题、冲突和名称依赖的类型

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

于 2013-09-02T08:24:12.500 回答