在.NET中使用Protobuf框架
protobuf是google的一个开源项目,可用于以下两种用途:
(1)数据的存储(序列化和反序列化),类似于xml、json等;
(2)制作网络通信协议。
源代码下载地址:https://github.com/mgravell/protobuf-net
开源项目地址如下:https://code.google.com/p/protobuf-net/,下载解压后的目录如下所示,每个文件夹的详细介绍都在最后一个txt文件里面了。
ProtoGen是用来根据***.proto文件生成对应的***.cs文件的,而做数据存储功能只需要用到protobuf-net.dll即可,至于使用哪个版本项目情况决定。下面的例子在Windows平台下新建一个C#的控制台工程,并引入ProtoBufNet\Full\net30\protobuf-net.dll,代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | namespace TestProtoBuf { [ProtoContract] public class Address { [ProtoMember(1)] public string Line1; [ProtoMember(2)] public string Line2; } [ProtoContract] public class Person { [ProtoMember(1)] public int Id; [ProtoMember(2)] public string Name; [ProtoMember(3)] public Address Addr; } class Program { static void Main( string [] args) { Person person = new Person(); person.Id = 1; person.Name = "First" ; person.Addr = new Address { Line1= "line1" , Line2= "line2" }; // ProtoBuf序列化 using ( var file = System.IO.File.Create( "Person.bin" )) { ProtoBuf.Serializer.Serialize(file, person); } // ProtoBuf反序列化 Person binPerson = null ; using ( var file = System.IO.File.OpenRead( "Person.bin" )) { binPerson = ProtoBuf.Serializer.Deserialize<Person>(file); } System.Console.WriteLine(binPerson.Name); } } } |
可以看到序列化和反序列化的代码非常简单。
protobuf提供了一种proto脚本用来编写***.proto文件,这种脚本格式简单、可读性强、方便扩展,用proto脚本定义网络协议是非常好用的。
下面是一个proto脚本的简单例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | message Person { required string name=1; required int32 id=2; optional string email=3; enum PhoneType { MOBILE=0; HOME=1; WORK=2; } message PhoneNumber { required string number=1; optional PhoneType type=2 [ default =HOME]; } repeated PhoneNumber phone=4; } |
requied是必须有的字段、optional是可有可无的字段、repeated是可以重复的字段(数组或列表),同时枚举字段都必须给出默认值。
接下来就可以使用ProgoGen来根据proto脚本生成源代码cs文件了,命令行如下:
protogen -i:test.proto -0:test.cs -ns:MyProtoBuf
-i指定了输入,-o指定了输出,-ns指定了生成代码的namespace,上面的proto脚本生成的源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ // Generated from: file/pb.proto namespace MyProtoBuf { [global::System.Serializable, global::ProtoBuf.ProtoContract(Name= @"Person" )] public partial class Person : global::ProtoBuf.IExtensible { public Person() {} private string _name; [global::ProtoBuf.ProtoMember(1, IsRequired = true , Name= @"name" , DataFormat = global::ProtoBuf.DataFormat.Default)] public string name { get { return _name; } set { _name = value; } } private int _id; [global::ProtoBuf.ProtoMember(2, IsRequired = true , Name= @"id" , DataFormat = global::ProtoBuf.DataFormat.TwosComplement)] public int id { get { return _id; } set { _id = value; } } private string _email = "" ; [global::ProtoBuf.ProtoMember(3, IsRequired = false , Name= @"email" , DataFormat = global::ProtoBuf.DataFormat.Default)] [global::System.ComponentModel.DefaultValue( "" )] public string email { get { return _email; } set { _email = value; } } private readonly global::System.Collections.Generic.List<Person.PhoneNumber> _phone = new global::System.Collections.Generic.List<Person.PhoneNumber>(); [global::ProtoBuf.ProtoMember(4, Name= @"phone" , DataFormat = global::ProtoBuf.DataFormat.Default)] public global::System.Collections.Generic.List<Person.PhoneNumber> phone { get { return _phone; } } [global::System.Serializable, global::ProtoBuf.ProtoContract(Name= @"PhoneNumber" )] public partial class PhoneNumber : global::ProtoBuf.IExtensible { public PhoneNumber() {} private string _number; [global::ProtoBuf.ProtoMember(1, IsRequired = true , Name= @"number" , DataFormat = global::ProtoBuf.DataFormat.Default)] public string number { get { return _number; } set { _number = value; } } private Person.PhoneType _type = Person.PhoneType.HOME; [global::ProtoBuf.ProtoMember(2, IsRequired = false , Name= @"type" , DataFormat = global::ProtoBuf.DataFormat.TwosComplement)] [global::System.ComponentModel.DefaultValue(Person.PhoneType.HOME)] public Person.PhoneType type { get { return _type; } set { _type = value; } } private global::ProtoBuf.IExtension extensionObject; global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject( bool createIfMissing) { return global::ProtoBuf.Extensible.GetExtensionObject( ref extensionObject, createIfMissing); } } [global::ProtoBuf.ProtoContract(Name= @"PhoneType" )] public enum PhoneType { [global::ProtoBuf.ProtoEnum(Name= @"MOBILE" , Value=0)] MOBILE = 0, [global::ProtoBuf.ProtoEnum(Name= @"HOME" , Value=1)] HOME = 1, [global::ProtoBuf.ProtoEnum(Name= @"WORK" , Value=2)] WORK = 2 } private global::ProtoBuf.IExtension extensionObject; global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject( bool createIfMissing) { return global::ProtoBuf.Extensible.GetExtensionObject( ref extensionObject, createIfMissing); } } } |
*********************分割线*********************

版本
|
说明
|
net20 | regular .NET 2.0 (excludes WCF hooks) |
net30 | regular .NET 3.0 or above (including 3.5, 4.0, 4.5, ...) |
netcore45 | windows store apps / windows runtime 4.5 |
sl4 | silverlight 4 or above |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?