访问协议缓冲区域的简便方法

时间:2012-04-13 21:06:08

标签: c# protocol-buffers

有这样的.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”,number可以等于0,对于第二个字段,可以等于1。获取object1重复的必要方法也是按字段名称计算的:

public int GetFieldCount(string fieldName)

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

3 个答案:

答案 0 :(得分:0)

与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();
}

现在xmlXmlSerializer实例中相同数据的Foo表示形式(以及任何子数据,例如Bar

答案 1 :(得分:0)

顺便说一句,如果您将代码生成扩展为以下内容会怎样:

[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”文字访问字段。你怎么看?

答案 2 :(得分:0)

嗯......绝对是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 。会回归它。 ;)