gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 22:14:19 25 4
gpt4 key购买 nike

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

我的程序(到目前为止)是使用 .Net 类作为定义类。我使用 protobuf-net Serializer.GetProto() 方法生成 .proto 文件,并使用 protostuff 的 protostuff-compiler 程序生成或多或少对应于 .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 以不同的方式做事;查看 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;
}

因此,此时您有几个选择:

  • 以完全不使用继承的方式对两种实现中的数据进行 reshape ——这样您就有了一个扁平的 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com