如果未设置字段值,则使用:数字类型为零,字符串为空字符串,布尔值为false。对于嵌入式消息,默认值始终是消息的“默认实例”或“原型”,没有设置任何字段。调用访问器以获取尚未显式设置的字段的值将始终返回该字段的默认值。
如果重复一个字段,则该字段可以重复任意次(包括零次)。重复值的顺序将保留在协议缓冲区中。将重复字段视为动态大小的数组。
在协议缓冲区语言指南中,您将找到有关编写.proto文件的完整指南-包括所有可能的字段类型。但是,不要去寻找类似于类继承的工具–协议缓冲区不能做到这一点。
编译协议缓冲区现在,您有了.proto,接下来需要做的是生成读取和写入AddressBook(以及Person和PhoneNumber)消息所需的类。 为此,您需要在.proto上运行协议缓冲区编译器协议:
如果尚未安装编译器,请下载软件包并按照自述文件中的说明进行操作。
现在运行编译器,指定源目录(应用程序的源代码所在的位置;如果您不提供值,则使用当前目录),目标目录(您希望生成的代码进入的位置;通常与$相同) SRC_DIR),以及.proto的路径。 在这种情况下,您将调用:
protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto因为需要C#代码,所以使用--csharp_out选项–其他受支持的语言也提供了类似的选项。
这将在您指定的目标目录中生成Addressbook.cs。 要编译此代码,您需要一个引用Google.Protobuf程序集的项目。
生成Addressbook.cs提供了五种有用的类型:
静态地址簿类,其中包含有关协议缓冲区消息的元数据。
具有只读People属性的AddressBook类。
具有“名称”,“ ID”,“电子邮件”和“电话”属性的Person类。
一个PhoneNumber类,嵌套在静态Person.Types类中。
一个PhoneType枚举,也嵌套在Person.Types中。
您可以在《 C#生成的代码》指南中详细了解确切生成的内容的详细信息,但是在大多数情况下,您可以将它们视为完全普通的C#类型。需要强调的一点是,对应于重复字段的任何属性都是只读的。您可以向集合中添加项目或从集合中删除项目,但是不能用完全独立的集合来替换它。重复字段的收集类型始终为RepeatedField 。此类型类似于List ,但有一些额外的便捷方法,例如,在大学初始化程序中使用的Add重载接受项目集合。
这是一个如何创建Person实例的示例:
Person john = new Person { Id = 1234, Name = "John Doe", Email = "jdoe@example.com", Phones = { new Person.Types.PhoneNumber { Number = "555-4321", Type = Person.Types.PhoneType.Home } } };请注意,在C#6中,可以使用static删除Person.Types的丑陋之处:
// Add this to the other using directives using static Google.Protobuf.Examples.AddressBook.Person.Types; ... // The earlier Phones assignment can now be simplified to: Phones = { new PhoneNumber { Number = "555-4321", Type = PhoneType.HOME } } 解析和序列化使用协议缓冲区的全部目的是对数据进行序列化,以便可以在其他位置对其进行解析。 每个生成的类都有一个WriteTo(CodedOutputStream)方法,其中CodedOutputStream是协议缓冲区运行时库中的类。 但是,通常您将使用一种扩展方法来写入常规System.IO.Stream或将消息转换为字节数组或ByteString。 这些扩展消息位于Google.Protobuf.MessageExtensions类中,因此,当您要序列化时,通常会希望对Google.Protobuf名称空间使用using指令。 例如:
using Google.Protobuf; ... Person john = ...; // Code as before using (var output = File.Create("john.dat")) { john.WriteTo(output); }解析也很简单。 每个生成的类都有一个静态的Parser属性,该属性返回该类型的MessageParser 。 反过来,它具有解析流,字节数组和ByteStrings的方法。 因此,要解析我们刚刚创建的文件,我们可以使用:
Person john; using (var input = File.OpenRead("john.dat")) { john = Person.Parser.ParseFrom(input); }Github存储库中提供了使用这些消息维护地址簿(添加新条目并列出现有条目)的完整示例程序。
扩展协议缓冲区在发布使用协议缓冲区的代码后早晚,您无疑会想要“改善”协议缓冲区的定义。如果您希望新的缓冲区向后兼容,而旧的缓冲区向后兼容,并且您几乎肯定希望这样做,那么您需要遵循一些规则。在新版本的协议缓冲区中:
您不得更改任何现有字段的标签号。
您可以删除字段。
您可以添加新字段,但必须使用新的标签号(即,该协议缓冲区中从未使用过的标签号,即使删除的字段也从未使用过)。
(这些规则有一些,但很少使用。)