[英]Does protobuf-net support nullable types?
是否可以在 protobuf-net 中生成可為空的成員?
message ProtoBuf1 {
optional Int32? databit = 1;
optional Nullable<bool> databool = 2;
}
是的,但如果您從 .proto 進行代碼生成,則默認情況下它不會生成它們。
如果這只是 C#,當然,您不需要.proto - 只需:
[ProtoContract]
public class ProgoBuf1
{
[ProtoMember(1)]
public int? Foo {get;set;}
[ProtoMember(2)]
public float? Bar {get;set;}
}
如果您是從.proto工作,你可以考慮復制和編輯csharp.xslt
以滿足您的首選布局。
這是我在使用需要 Protocol Buffers 版本 3 的 Google 的 Protobuf .NET API 時針對可空類型的解決方案。(請注意,這不是使用 Marc Gravell 的 protobuf-net,因此這不是所問問題的確切答案。)
在NullableInt32.proto
:
syntax = "proto3";
message NullableInt32 {
int32 value = 1;
}
在NullableInt32Extensions.cs
:
public static class NullableInt32Extensions
{
public static bool HasValue(this NullableInt32 source)
{
return source != null;
}
}
public partial class NullableInt32
{
public static implicit operator int? (NullableInt32 other)
{
return other == null ? (int?)null : other.Value;
}
public static implicit operator NullableInt32(int? other)
{
return other == null ? null : new NullableInt32 { Value = other.Value };
}
}
此模式可用於任何 Protobuf 非長度分隔標量值 - double
、 float
、 int32
、 int64
、 uint32
、 uint64
、 sint32
、 sint64
、 fixed32
、 fixed64
、 sfixed32
、 sfixed64
和bool
。
這是所有這些的工作原理。 假設您有一個包含NullableInt32
字段的Record
消息,在這個人為的示例中,它是唯一的字段。
在Record.proto
:
syntax = "proto3";
import "NullableInt32.proto";
message Record {
NullableInt32 id = 1;
}
一旦使用 Google 的protoc.exe
將其編譯為 C#,您就可以將Id
屬性幾乎完全視為Nullable<int>
。
var r = new Record();
// r.Id is null by default, but we can still call HasValue()
// because extension methods work on null references.
r.Id.HasValue(); // => false
// We can explicitly set Id to null.
r.Id = null;
// We can set Id to a primitive numeric value directly
// thanks to our implicit conversion operators.
r.Id = 1;
// We can also use NullableInt32 in any context that expects a
// Nullable<int>. The signature of the following method is
// bool Equals(int?, int?).
Nullable.Equals<int>(r.Id, 1); // => true
// We can explicitly set Id to a NullableInt32.
r.Id = new NullableInt32 { Value = 1 };
// Just like Nullable<int>, we can get or set the Value of a
// NullableInt32 directly, but only if it's not null. Otherwise,
// we'll get a NullReferenceException. Use HasValue() to avoid this.
if(r.Id.HasValue())
r.Id.Value.ToString(); // => "1"
// Setting Id to 0 is the same as setting Id to a new
// NullableInt32 since the default value of int32 is 0.
// The following expressions are equivalent.
r.Id = 0;
r.Id = new NullableInt32();
r.Id = new NullableInt32 { Value = 0 };
r.Id.Value = 0; // as long as Id is not null
最后,讓我們看看我們的Record
消息將如何通過具有不同Id
值的線路傳輸。
var r = new Record();
// When Id is null, Record is empty since it has no other fields.
// Explicitly setting Id to null will have the same effect as
// never setting it at all.
r.Id = null;
r.ToByteArray(); // => byte[0]
// Since NullableInt32 is a Protobuf message, it's encoded as a
// length delimited type. Setting Id to 1 will yield four bytes.
// The first two indicate the type and length of the NullableInt32
// message, and the last two indicate the type and value held within.
r.Id = 1;
r.ToByteArray(); // => byte[] {
// 0x0a, // field = 1, type = 2 (length delimited)
// 0x02, // length = 2
// 0x08, // field = 1, type = 0 (varint)
// 0x01, // value = 1
// }
// When Id is set to the default int32 value of 0, only two bytes
// are needed since default values are not sent over the wire.
// These two bytes just indicate that an empty NullableInt32 exists.
r.Id = 0;
r.ToByteArray(); // => byte[] {
// 0x0a, // field = 1, type = 2 (length delimited)
// 0x00, // length = 0
// }
導入“wrappers.proto”支持可空值:
例子:
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message ProtoPerson {
google.protobuf.StringValue firstName = 1;
google.protobuf.StringValue lastName = 2;
google.protobuf.StringValue address1 = 3;
google.protobuf.Int32Value age = 4;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.