访问协议缓冲区字段的简单方法
本文关键字:简单 方法 字段 协议 缓冲区 访问 | 更新日期: 2023-09-27 18:30:58
有这样的 .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 可以是可重复的。是否可以编写通用方法,将字段值作为基本对象(如整数、布尔值、字符串、日期时间或简单的字符串)返回?我想通过字符串文字获得以下访问权限:
public object GetFieldValue(int number, string fullPath)
其中可以像这样指定 fullPath,例如:
fullPath = "object1.Object1field1";
重复字段所需的数字:例如,第一个"object1"的数字可以等于 0,第二个数字可以等于 1。按字段名称获取对象 1 重复计数也是必要的方法:
public int GetFieldCount(string fieldName)
并且还需要类似的方法来访问任何嵌套级别的子对象。这可能吗?是否有协议缓冲区硬编码类的替代方法?
与 xml/protobuf 对话有关; 我的理解是protobuf-csharp-port使用不可变类型,因此不能很好地与XmlSerializer之类的东西一起使用。 相比之下,protobuf-net故意开始使用标准的可变POCO类型,要么是你现有的DTO,要么是通过protprotogen从.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();
}
现在xml
是Foo
实例中相同数据(以及任何子数据,如Bar
)中相同数据的XmlSerializer
表示
顺便说一句,如果你将代码生成扩展到这样的东西会怎样:
[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-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。会回到它。;)