在.NET 7.0的gRPC PROTO3中如何定义可空字段?
我正在使用.NET Core 7.0进行开发,以下是我的vendor.proto文件代码:
syntax = "proto3"; option csharp_namespace = "IndustryAPI.Protos"; message ListOfStrings { repeated string strings = 1; } enum VendorMode { VendorMode_UNSPECIFIED = 0; Shopping = 1; Discovery = 2; ShoppingAndDiscovery = 3; } message VendorModel { string Id = 1; string Name = 2; string Channel = 3; string Address = 4; string ContactNummber = 5; string Email = 6; string Web = 7; } service VendorService { rpc GetVendorBasicDetails(GetVendorBasicDetailsRequest) returns (GetVendorBasicDetailsResponse); } // requests message GetVendorBasicDetailsRequest { string channelId = 1; string VendorCreatedDateStart = 2; string VendorCreatedDateEnd = 3; } message GetVendorBasicDetailsResponse { repeated VendorModel Vendor = 1; }
运行时抛出异常:
Exception was thrown by handler. ArgumentNullException: Value cannot be null
其中VendorModel中的Web字段需要设为可空值,请问该如何在PROTO3中定义可空字段?
在Proto3中,原生基本类型(如string)默认生成的C#代码为不可空引用类型(.NET Core 7.0默认启用nullable引用类型规则),赋值null时会触发ArgumentNullException。实现可空字段有两种常用方案:
方案一:使用Google官方包装类型(跨语言兼容推荐)
Google提供了专门的包装类型处理可空场景,需引入google/protobuf/wrappers.proto,用StringValue替代原生string类型:
修改后的VendorModel定义:
import "google/protobuf/wrappers.proto"; message VendorModel { string Id = 1; string Name = 2; string Channel = 3; string Address = 4; string ContactNummber = 5; string Email = 6; google.protobuf.StringValue Web = 7; }
生成的C#代码中,Web会被转为StringValue?类型,支持直接赋值null,序列化时null值会被正确识别为未设置字段。
方案二:启用Proto3的nullable特化选项(.NET生态专属)
若使用最新版Grpc.Tools,可在.proto文件头部添加option nullable = "enable";,让原生基本类型直接生成可空C#引用类型:
修改后的.proto头部:
syntax = "proto3"; option csharp_namespace = "IndustryAPI.Protos"; option nullable = "enable";
此时VendorModel中的string Web = 7;生成的C#代码会是string? Web { get; set; },无需额外修改即可支持null赋值。
注意:该选项为.NET特有,若需跨语言兼容优先选方案一;仅在.NET生态内使用时,方案二更简洁。
内容的提问来源于stack exchange,提问作者Dilakshan AT

