C# 访问协议缓冲区字段的简便方法

C# 访问协议缓冲区字段的简便方法,c#,protocol-buffers,C#,Protocol Buffers,有这样的.proto文件结构 { session{ field1 = value; field2 = value; ... } object1{ Object1field1 = value; Object1field2 = value; ... } object1{ Object1field1 = value; Object1field2 = value; ... } object2{ Object2

有这样的.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或string)返回?我希望通过字符串文字获得以下访问权限:

public object GetFieldValue(int number, string fullPath)
其中,完整路径可以这样指定,例如:

fullPath = "object1.Object1field1";
重复字段所需的数字:例如,第一个object1的数字可以等于0,第二个object1的数字可以等于1。获取object1的另一个必要方法是按字段名重复计数:

public int GetFieldCount(string fieldName)

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

与xml/protobuf对话相关;我的理解是protobuf csharp端口使用不可变的类型,因此不能很好地处理XmlSerializer之类的东西。相比之下,protobuf net故意使用标准的可变POCO类型,既可以使用现有的DTO,也可以通过ProtoGen从.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;}
}

i、 要从同一接口IGetFieldsByName继承所有类?这样就可以很容易地实现我喜欢的行为:按object.name literal访问字段。你觉得怎么样?

嗯。。。protobuf csharp端口具有执行此任务所需的一切,例如:

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派生的所有类型。我会回来的

您当前使用的是什么协议缓冲区库?似乎protobuf csharp端口,他们为我的项目提供了预生成的类和Google.ProtocolBuffers.dll。哪一个更适合这样的任务?这两个C协议缓冲区库的文档和示例非常少。我还可以问:在我看来,实现这一点的主要方法是反序列化数据,然后使用反射或类似FastMember的东西按名称获取值。这是一种选择吗?如果您不知道对象定义,则无法按名称访问,因为protobuf不存储名称。是的,数据是反序列化的。当然,我知道对象定义,但我希望使用一些通用方法通过存储的用户定义设置映射(如object1.Object1field1)访问流程字段。因为我有数百个字段,我想自动读取。在其他情况下,我需要硬编码每一个-不是很好。为什么pbuff不提供这样的服务?!在这种情况下,它不如XML那么方便。为什么不将其反序列化为一些可以自动访问的更简单的结构,例如:Dictionary,其中string是字段名,object可以是:int、string、bool、datetime和嵌套级别的next Dictionary?如果protobuf net生成这样的类,在这种情况下,我更喜欢您的实现,我将尝试它而不是protobuf csharp端口。若Bar是可重复的,那个么在你们的例子中protobuf网络会产生什么呢?酷,比protobuf csharp端口更容易使用和理解的数据结构——这实际上很糟糕。有了protobuf网络,通过反射访问字段和实现我需要的访问就容易多了。@AlekseyK那么,你打算使用XmlSerializer吗?还是数据序列化程序?特别是,XmlSerializer和DataContractSerializer的属性是互斥的,我不只是为了搞笑而添加这个限制。。。。既然您谈论的是xml,我就假设XmlSerializer是您最好的选择Tanks,Marc,selected XmlSerializer.BTW,您的protobuf net生成的类或库是否有一些内部反射:按名称访问字段值?或者按名称访问它们的唯一方法是使用C反射或FastMember?我这样问是因为对所有属性的思想迭代可能非常慢,不是吗?我认为这与协议缓冲区无关protobuf从不使用名称。。。我明白了,不过protobuf csharp端口有一些。请按照您之前的建议,将VS2008.Net 3.5的fast member DLL用于下载谷歌代码部分,好吗?我今天都在开会,但稍后会做。谢谢,可能有人会需要它。顺便说一句,只需阅读版本2.4.1的发行说明-它允许:-添加Google.ProtoBuffers.Serialization程序集,以支持在XML、JSON、IDictionary和其他文件之间读取和写入消息。这太完美了!!!