【问题标题】:Easy way to access protocol buffer field访问协议缓冲区字段的简单方法
【发布时间】:2012-04-13 21:06:07
【问题描述】:

有这样的.proto文件结构

{
    session{
    field1 = value;
    field2 = value;
    ...
    }
object1{
    Object1field1 = value;
    Object1field2 = value;
    ...
}
object1{
    Object1field1 = value;
    Object1field2 = value;
    ...
}
object2{
    Object2field1 = value;
    Object2field2 = value;
    ...
    SubObject1{
    SubObject1field1 = value;
    SubObject2field2 = value;
    ...
    }
}    object2{
    Object2field1 = value;
    Object2field2 = value;
    ...
    SubObject1{
    SubObject1field1 = value;
    SubObject2field2 = value;
    ...
    }
}

} 简单地说具有复杂的层次结构。例如,Object1 或 Object2 可以是可重复的。是否可以编写通用方法,将字段值作为基础对象(如 int、bool、string、datetime 或简单的字符串)返回?我想通过字符串文字获得以下访问权限:

public object GetFieldValue(int number, string fullPath)

fullPath 可以这样指定,例如:

fullPath = "object1.Object1field1";

重复字段所需的数字:例如,对于第一个“object1”,数字可以等于 0,而对于第二个,数字可以等于 1。获取object1的必要方法也是按字段名称重复计数:

public int GetFieldCount(string fieldName)

并且还需要类似的方式来访问子对象到任何嵌套级别。那可能吗?是否有替代协议缓冲区硬编码类的方法?

【问题讨论】:

  • 您目前使用的是什么协议缓冲区库?
  • 似乎是 protobuf-csharp-port,它们为我的项目提供了预生成的类和 Google.ProtocolBuffers.dll。哪一个更适合这样的任务?这两个 C# Protocol Buffers 库的文档和示例都很少。
  • 我还可以问:在我看来,这样做的主要方法是反序列化数据,然后使用反射(或类似 FastMember 的东西)按名称获取值。这是一个选项吗?如果不知道对象定义,则无法通过名称访问,因为 protobuf 不存储名称。
  • 是的,数据已反序列化。当然我知道对象定义,但我想通过存储的用户定义设置(映射)来访问流程字段的一些通用方法,比如提到的“object1.Object1field1”。因为我有数百个我想自动阅读的字段。在其他情况下,我需要对每个进行硬编码 - 不是很好。为什么 pbuff 不提供这样的?!在这种情况下,它不如 XML 方便。
  • 为什么不将其反序列化为一些可以自动访问的更简单的结构,例如:Dictionary,例如,其中 string 是字段名称,而 object 可以是:int, string,嵌套级别的布尔值、日期时间和下一个字典

标签: c# protocol-buffers


【解决方案1】:

与 xml/protobuf 对话有关;我的理解是 protobuf-csharp-port 使用不可变类型,因此不适用于 XmlSerializer 之类的东西。相比之下,protobuf-net 有意使用标准可变 POCO 类型,无论是您现有的 DTO,还是通过 protoprotogen 从 .proto 生成;无论哪种方式,我们最终都会生成一个类似的类型:

[ProtoContract]
public class Foo {
    [ProtoMember(1)]
    public string Name {get;set;}
    [ProtoMember(2)]
    public Bar Something {get;set;}
}
[ProtoContract]
public class Bar {
    [ProtoMember(1)]
    public int Id {get;set;}
}

(给予或采取一些复杂性)

那么从 protobuf 流转换为 xml 很简单:

Foo foo;
using(var source = ...) {
    foo = Serializer.Deserialize<Foo>(source);
}
string xml;
using(var sw = new StringWriter()) {
    var ser = new Serializer(typeof(Foo));
    ser.Serialize(sw, foo);
    xml = sw.ToString();
}

现在xmlFoo 实例中相同数据的XmlSerializer 表示(以及任何子数据,例如Bar

【讨论】:

  • 如果 protobuf-net 生成这样的类,在那种情况下,我更喜欢你的实现,将尝试它而不是 protobuf-csharp-port。如果 Bar 是可重复的,那么 protobuf-net 会在 You 示例中生成什么?
  • 酷,比 protobuf-csharp-port 更容易使用和理解的数据结构——这实际上很糟糕。使用您的 protobuf-net,可以更轻松地通过反射访问字段并实现我需要的访问。
  • @AlekseyK 好吧,你打算使用 XmlSerializer 吗?还是 DataContractSerializer?特别是,XmlSerializer 和 DataContractSerializer 的属性 是互斥的(我添加这个限制并不是为了傻笑……)。既然你在谈论 xml,我会假设 XmlSerializer 是你最好的选择
  • 谢谢,Marc,也选择了 XmlSerializer。
  • 顺便说一句,您的 protobuf-net 生成的类或库是否有一些内部反射:按名称访问字段值?或者通过名称访问它们的唯一方法是使用 C# 反射或 FastMember?我问是因为认为所有属性的迭代可能非常慢,不是吗?
【解决方案2】:

顺便说一句,如果您将您的代码生成扩展到这样的内容:

[ProtoContract]
public class Foo : IGetFieldsByName {
    [ProtoMember(1)]
    public string Name {get;set;}
    [ProtoMember(2)]
    public Bar Something {get;set;}
}
[ProtoContract]
public class Bar : IGetFieldsByName {
    [ProtoMember(1)]
    public int Id {get;set;}
}

即从同一接口 IGetFieldsByName 继承所有类?然后很容易实现我喜欢的行为:通过“object.name”字面量访问字段。你怎么看?

【讨论】:

  • 我认为这与协议缓冲区无关(protobuf 从不使用名称......永远)。
  • 我明白了,但是 protobuf-csharp-port 有一些。您能否按照您之前的建议将 VS2008 (.Net 3.5) 的快速成员 dll 放入 Google 代码的下载部分?
  • 我今天都在开会,但稍后会开会
  • 谢谢,可能有人需要它。
【解决方案3】:

嗯...肯定 protobuf-csharp-port 拥有此任务所需的一切,例如:

IMessage object2 = (IMessage)original[original.DescriptorForType.FindFieldByName("object2"), 0];
IMessage subObject1 = (IMessage)object2[object2.DescriptorForType.FindFieldByName("SubObject1")];
int value = (int)subObject1[subObject1.DescriptorForType.FindFieldByName("SubObject1Field1")];

与从 IMessage 派生的所有类型一样。将回到它。 ;)

【讨论】:

  • 顺便说一句,刚刚阅读了版本 2.4.1 的发布说明 - 它允许: - 添加“Google.ProtoBuffers.Serialization”程序集以支持从 XML、JSON 读取和写入消息, IDictionary 等。这是完美的!!!
猜你喜欢
  • 2017-02-12
  • 2011-09-18
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 2014-09-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
相关资源
最近更新 更多