gRPC 使用 Protobuf 作为其接口定义语言 (IDL)。 消息是 Protobuf 中的主要数据传输对象。 它们在概念上类似于 .NET 类。
syntax = "proto3";
option csharp_namespace = "Contoso.Messages";
message Person {
int32 id = 1;
string first_name = 2;
string last_name = 3;
}
前面的消息定义将三个字段指定为名称/值对。 与 .NET 类型上的属性类似,每个字段都有名称和类型。 字段类型可以是 Protobuf 标量值类型(如 int32),也可以是其他消息。
Protobuf 样式指南建议使用 underscore_separated_names 作为字段名称。 为 .NET 应用创建的新 Protobuf 消息应遵循 Protobuf 样式准则。 .NET 工具会自动生成使用 .NET 命名标准的 .NET 类型。 例如,first_name Protobuf 字段生成 FirstName .NET 属性。
值类型对应表
.proto 类型
|
C# 类型
|
备注
|
double
|
double
|
|
float
|
float
|
|
int32
|
int
|
使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint32。
|
int64
|
long
|
使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint64。
|
uint32
|
uint
|
|
uint64
|
ulong
|
|
sint32
|
int
|
使用可变长编码方式。有符号的整型值。编码时比通常的int32高效。
|
sint64
|
long
|
使用可变长编码方式。有符号的整型值。编码时比通常的int64高效。
|
fixed32
|
uint
|
|
fixed64
|
ulong
|
|
sfixed32
|
int
|
总是4个字节。
|
sfixed64
|
long
|
总是8个字节。
|
bool
|
bool
|
|
string
|
string
|
|
bytes
|
ByteString
|
可能包含任意顺序的字节数据
|
值类型始终具有默认值,并且该默认值不能设置为 null 。此项约束包括 string 和 ByteString,他们都属于 C# 类。 string 默认为空字符串,ByteString 默认为空字节值。尝试将他们设置为 null 会引发错误。
可为 null 的类型
C# 的 Protobuf 代码生成使用本地类型,如 int 表示 int32。 因此这些值始终包括在内,不能为 null。对于需要显式 null 的值(例如在 C# 代码中使用 int?),Protobuf 的“已知类型”包括编译为可以为 null 的 C# 类型的包装器。 若要使用它们,请将 wrappers.proto 导入到 .proto 文件中,如以下代码所示:
syntax = "proto3"
import "google/protobuf/wrappers.proto"
message Person {
// ...
google.protobuf.Int32Value age = 5;
}
wrappers.proto 类型不会在生成的属性中公开。 Protobuf 会自动将它们映射到 C# 消息中相应的可为 null 的 .NET 类型。 例如,google.protobuf.Int32Value 字段生成 int? 属性。 引用类型属性(如 string 和 ByteString )保持不变,但可以向它们分配 null,这不会引发错误。
C# 类型
|
类型包装器
|
bool?
|
google.protobuf.BoolValue
|
double?
|
google.protobuf.DoubleValue
|
float?
|
google.protobuf.FloatValue
|
int?
|
google.protobuf.Int32Value
|
long?
|
google.protobuf.Int64Value
|
uint?
|
google.protobuf.UInt32Value
|
ulong?
|
google.protobuf.UInt64Value
|
string
|
google.protobuf.StringValue
|
ByteString
|
google.protobuf.BytesValue
|
集合
列表
Protobuf 中,在字段上使用 repeated 前缀关键字指定列表。
message Person {
// ...
repeated string roles = 8;
}
在生成的代码中,repeated 字段由 Google.Protobuf.Collections.RepeatedField<T> 泛型类型表示。
public class Person
{
// ...
public RepeatedField<string> Roles { get; }
}
RepeatedField<T> 实现了 IList<T> 接口,因此可以应用 LINQ 查询,或者将其转换为数组或列表。 RepeatedField<T> 属性没有公开的设置器,所以他在内部保证了不可为空。需要向其中添加数据时调用 Add 方法即可:
var person = new Person();
// Add one item.
person.Roles.Add("user");
// Add all items from another collection.
var roles = new [] { "admin", "manager" };
person.Roles.Add(roles);
字典
.NET IDictionary<TKey,TValue> 类型在 Protobuf 中使用 map 表示。
message Person {
// ...
map<string, string> attributes = 9;
}
在生成的 .NET 代码中,map 字段由 Google.Protobuf.Collections.MapField<TKey, TValue> 泛型类型表示。 MapField <TKey, TValue> 实现了 IDictionary <TKey, TValue> 接口。 与 repeated 属性一样,map 属性没有公开的设置器 。
var person = new Person();
// Add one item.
person.Attributes["created_by"] = "James";
// Add all items from another collection.
var attributes = new Dictionary<string, string>
{
["last_modified"] = DateTime.UtcNow.ToString()
};
person.Attributes.Add(attributes);