访问协议缓冲区字段的简单方法

本文关键字:简单 方法 字段 协议 缓冲区 访问 | 更新日期: 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();
}

现在xmlFoo实例中相同数据(以及任何子数据,如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。会回到它。;)