在 gRPC/proto3 中设置 oneof 请求的更有效方法
More efficient way to set a oneof request in gRPC/proto3
在 PHP 客户端和 Python 服务器上拥有此 proto3 模式:
service GetAnimalData{
rpc GetData (AnimalRequest) returns (AnimalData) {}
}
message AnimalRequest {
OneOfAnimal TypeAnimal = 1;
}
message AnimalData {
repeated int32 data = 1;
}
message OneOfAnimal {
oneof animal_oneof {
CAT cat = 1;
DOG dog = 2;
}
}
message CAT{
int32 p = 1;
int32 d = 2;
int32 q = 3;
}
message DOG{
int32 p = 1;
int32 d = 2;
int32 q = 3;
int32 p2 = 4;
int32 d2 = 5;
int32 q2 = 6;
}
为了设置来自 PHP 客户端的请求,我需要做:
- 新建一个
CAT
- 设置
OneOfAnimal
为CAT
- 设置
AnimalRequest.TypeAnimal
为OneOfAnimal
是否有 proto3 的架构,我可以直接将 CAT
或 DOG
对象设置为我的 AnimalRequest.TypeAnimal
笼统地说;不,不是真的。
在某些非常具体的情况下,答案是"yes" - 例如,protobuf-net(.NET 中的 "code-first" protobuf 实现)发生以这种方式在 exactly 中实现继承,因此您可以使用:
[ProtoContract]
public class AnimalRequest {
[ProtoMember(1)] public Animal Animal {get;set;}
}
[ProtoContract]
[ProtoInclude(1, typeof(Cat))]
[ProtoInclude(2, typeof(Dog))]
class Animal {} // acts identically to your OneOfAnimal message type
[ProtoContract]
class Cat {
[ProtoMember(1)] public int P {get;set;}
[ProtoMember(2)] public int D {get;set;}
[ProtoMember(3)] public int Q {get;set;}
}
[ProtoContract]
class Dog {
[ProtoMember(1)] public int P {get;set;}
[ProtoMember(2)] public int D {get;set;}
[ProtoMember(3)] public int Q {get;set;}
[ProtoMember(4)] public int P2 {get;set;}
[ProtoMember(5)] public int D2 {get;set;}
[ProtoMember(6)] public int Q2 {get;set;}
}
然后你使用:
var result = svc.GetData(
new AnimalRequest { Animal = new Dog { P = 42, ... Q2 = 19 } }
);
它会以完全相同的方式工作 - 将发送相同的字节;本质上,protobuf-net 将继承视为 oneof
(在类型层次结构的每个级别)。
但是:因为 .proto
旨在以非常通用的 "least common denominator" 方式工作,.proto
本身 没有继承的概念,所以:您不能从 .proto
或 Google 库中执行此操作。
在 PHP 客户端和 Python 服务器上拥有此 proto3 模式:
service GetAnimalData{
rpc GetData (AnimalRequest) returns (AnimalData) {}
}
message AnimalRequest {
OneOfAnimal TypeAnimal = 1;
}
message AnimalData {
repeated int32 data = 1;
}
message OneOfAnimal {
oneof animal_oneof {
CAT cat = 1;
DOG dog = 2;
}
}
message CAT{
int32 p = 1;
int32 d = 2;
int32 q = 3;
}
message DOG{
int32 p = 1;
int32 d = 2;
int32 q = 3;
int32 p2 = 4;
int32 d2 = 5;
int32 q2 = 6;
}
为了设置来自 PHP 客户端的请求,我需要做:
- 新建一个
CAT
- 设置
OneOfAnimal
为CAT
- 设置
AnimalRequest.TypeAnimal
为OneOfAnimal
是否有 proto3 的架构,我可以直接将 CAT
或 DOG
对象设置为我的 AnimalRequest.TypeAnimal
笼统地说;不,不是真的。
在某些非常具体的情况下,答案是"yes" - 例如,protobuf-net(.NET 中的 "code-first" protobuf 实现)发生以这种方式在 exactly 中实现继承,因此您可以使用:
[ProtoContract]
public class AnimalRequest {
[ProtoMember(1)] public Animal Animal {get;set;}
}
[ProtoContract]
[ProtoInclude(1, typeof(Cat))]
[ProtoInclude(2, typeof(Dog))]
class Animal {} // acts identically to your OneOfAnimal message type
[ProtoContract]
class Cat {
[ProtoMember(1)] public int P {get;set;}
[ProtoMember(2)] public int D {get;set;}
[ProtoMember(3)] public int Q {get;set;}
}
[ProtoContract]
class Dog {
[ProtoMember(1)] public int P {get;set;}
[ProtoMember(2)] public int D {get;set;}
[ProtoMember(3)] public int Q {get;set;}
[ProtoMember(4)] public int P2 {get;set;}
[ProtoMember(5)] public int D2 {get;set;}
[ProtoMember(6)] public int Q2 {get;set;}
}
然后你使用:
var result = svc.GetData(
new AnimalRequest { Animal = new Dog { P = 42, ... Q2 = 19 } }
);
它会以完全相同的方式工作 - 将发送相同的字节;本质上,protobuf-net 将继承视为 oneof
(在类型层次结构的每个级别)。
但是:因为 .proto
旨在以非常通用的 "least common denominator" 方式工作,.proto
本身 没有继承的概念,所以:您不能从 .proto
或 Google 库中执行此操作。