protobuf是一个语言无关、平台无关的序列化协议,由谷歌开源提供。再加上其高性能、存储占用更小等特点,在云原生的应用中越来越广泛。
在C#中主要有两种方法来使用protobuf协议,nuget包分别为Google.Protobuf和protobuf-net,其中Google.Protobuf由谷歌官方提供。本文简要记录和展示Google.Protobuf的使用方法和特点。
需要用到的nuget有如下两个:Google.Protobuf、Google.Protobuf.Tools,其中Google.Protobuf是主类库,运行时要用到。Google.Protobuf.Tools提供了命令行工具,用于根据.proto文件转为目标语言的类型,仅开发时使用,运行时不需要。
本次Demo使用的.proto文件内容如下:
syntax = "proto3";
option cc_enable_arenas = true;
package Tccc.Demo.Protobuf;
message ErrorLog {
string LogID = 1;
string Context = 2;
string Stack = 3;
}
首先需要根据.proto文件生成目标类型,操作如下:
./google.protobuf.tools\3.19.1\tools\windows_x64\protoc.exe --csharp_out=./generatedCode ./proto/ErrorLog.proto
其中--csharp_out选项是生成C#语言的目标类型,运行protoc.exe -h 查看帮助信息,可以看到还支持一下几种选项:
--proto_path=PATH
--cpp_out=OUT_DIR Generate C++ header and source.
--csharp_out=OUT_DIR Generate C# source file.
--java_out=OUT_DIR Generate Java source file.
--js_out=OUT_DIR Generate JavaScript source.
--kotlin_out=OUT_DIR Generate Kotlin file.
--objc_out=OUT_DIR Generate Objective-C header and source.
--php_out=OUT_DIR Generate PHP source file.
--python_out=OUT_DIR Generate Python source file.
--ruby_out=OUT_DIR Generate Ruby source file.
运行上述命令,会根据指定的ErrorLog.proto文件生成ErrorLog.cs文件,文件中就是C#类型ErrorLog。生成的代码中会给此类型增加方法void WriteTo(CodedOutputStream output)和只读属性Parser,接下来进行序列化和反序列化的关键。
生成的ErrorLog类的完整代码:
//
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Tccc.Demo.Protobuf {
///
public static partial class ErrorLogReflection {
#region Descriptor
/// <summary>File descriptor for ProtoFiles/ErrorLog.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static ErrorLogReflection() {
byte\[\] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChlQcm90b0ZpbGVzL0Vycm9yTG9nLnByb3RvEhJUY2NjLkRlbW8uUHJvdG9i",
"dWYiOQoIRXJyb3JMb2cSDQoFTG9nSUQYASABKAkSDwoHQ29udGV4dBgCIAEo",
"CRINCgVTdGFjaxgDIAEoCUID+AEBYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor\[\] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo\[\] {
new pbr::GeneratedClrTypeInfo(typeof(global::Tccc.Demo.Protobuf.ErrorLog), global::Tccc.Demo.Protobuf.ErrorLog.Parser, new\[\]{ "LogID", "Context", "Stack" }, null, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class ErrorLog : pb::IMessage
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public static pbr::MessageDescriptor Descriptor {
get { return global::Tccc.Demo.Protobuf.ErrorLogReflection.Descriptor.MessageTypes\[0\]; }
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public ErrorLog() {
OnConstruction();
}
partial void OnConstruction();
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public ErrorLog(ErrorLog other) : this() {
logID\_ = other.logID\_;
context\_ = other.context\_;
stack\_ = other.stack\_;
\_unknownFields = pb::UnknownFieldSet.Clone(other.\_unknownFields);
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public ErrorLog Clone() {
return new ErrorLog(this);
}
/// <summary>Field number for the "LogID" field.</summary>
public const int LogIDFieldNumber = 1;
private string logID\_ = "";
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public string LogID {
get { return logID\_; }
set {
logID\_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "Context" field.</summary>
public const int ContextFieldNumber = 2;
private string context\_ = "";
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public string Context {
get { return context\_; }
set {
context\_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "Stack" field.</summary>
public const int StackFieldNumber = 3;
private string stack\_ = "";
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public string Stack {
get { return stack\_; }
set {
stack\_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public override bool Equals(object other) {
return Equals(other as ErrorLog);
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public bool Equals(ErrorLog other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (LogID != other.LogID) return false;
if (Context != other.Context) return false;
if (Stack != other.Stack) return false;
return Equals(\_unknownFields, other.\_unknownFields);
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public override int GetHashCode() {
int hash = 1;
if (LogID.Length != 0) hash ^= LogID.GetHashCode();
if (Context.Length != 0) hash ^= Context.GetHashCode();
if (Stack.Length != 0) hash ^= Stack.GetHashCode();
if (\_unknownFields != null) {
hash ^= \_unknownFields.GetHashCode();
}
return hash;
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE\_PROTOBUF\_REFSTRUCT\_COMPATIBILITY\_MODE
output.WriteRawMessage(this);
#else
if (LogID.Length != 0) {
output.WriteRawTag(10);
output.WriteString(LogID);
}
if (Context.Length != 0) {
output.WriteRawTag(18);
output.WriteString(Context);
}
if (Stack.Length != 0) {
output.WriteRawTag(26);
output.WriteString(Stack);
}
if (\_unknownFields != null) {
\_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE\_PROTOBUF\_REFSTRUCT\_COMPATIBILITY\_MODE
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (LogID.Length != 0) {
output.WriteRawTag(10);
output.WriteString(LogID);
}
if (Context.Length != 0) {
output.WriteRawTag(18);
output.WriteString(Context);
}
if (Stack.Length != 0) {
output.WriteRawTag(26);
output.WriteString(Stack);
}
if (\_unknownFields != null) {
\_unknownFields.WriteTo(ref output);
}
}
#endif
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public int CalculateSize() {
int size = 0;
if (LogID.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(LogID);
}
if (Context.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Context);
}
if (Stack.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Stack);
}
if (\_unknownFields != null) {
size += \_unknownFields.CalculateSize();
}
return size;
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public void MergeFrom(ErrorLog other) {
if (other == null) {
return;
}
if (other.LogID.Length != 0) {
LogID = other.LogID;
}
if (other.Context.Length != 0) {
Context = other.Context;
}
if (other.Stack.Length != 0) {
Stack = other.Stack;
}
\_unknownFields = pb::UnknownFieldSet.MergeFrom(\_unknownFields, other.\_unknownFields);
}
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE\_PROTOBUF\_REFSTRUCT\_COMPATIBILITY\_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
\_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(\_unknownFields, input);
break;
case 10: {
LogID = input.ReadString();
break;
}
case 18: {
Context = input.ReadString();
break;
}
case 26: {
Stack = input.ReadString();
break;
}
}
}
#endif
}
#if !GOOGLE\_PROTOBUF\_REFSTRUCT\_COMPATIBILITY\_MODE
\[global::System.Diagnostics.DebuggerNonUserCodeAttribute\]
\[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)\]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
\_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(\_unknownFields, ref input);
break;
case 10: {
LogID = input.ReadString();
break;
}
case 18: {
Context = input.ReadString();
break;
}
case 26: {
Stack = input.ReadString();
break;
}
}
}
}
#endif
}
#endregion
}
#endregion Designer generated code
public static byte\[\] Serialize(ErrorLog log)
{
using (MemoryStream output = new MemoryStream())
{
log.WriteTo(output);
return output.ToArray();
}
}
ErrorLog desErrorLog= ErrorLog.Parser.ParseFrom(data);
手机扫一扫
移动阅读更方便
你可能感兴趣的文章