protobuf-net使用
Protobuf-net介绍
由于项目中客户端和服务器都是用C#定义协议,所以使用protobuf-net来序列化,网上看了关于protobuf-net的中文文档比较少,为了防止大家少走弯路,所以进行一下整理。
Protobuf-net是一个.NET中关于protobuf buffers的库,更多关于protocol-buffers的使用和说明可以参照Google的文档。
我们可以通过NuGet控制台来安装或者直接通过NuGet界面来安装。
Protocol Buffers不适合用来处理大的消息,如果协议中每个消息都很大的话,我们可以考虑使用其他的方案。Protocol Buffers更适合处理结构化的数据集合。通常,结构化的数据集合都是由小的数据结构组成的。
使用方法
protobuf-net 提供了两种方式来标记类文件,一种是使用标签一种是不用标签,但是我们必须自己注册数据。
下面让我们来看一个例子
[ProtoContract] public class Person { [ProtoMember(1)] public int Id { get; set; } [ProtoMember(2)] public string Name { get; set; } [ProtoMember(3)] public Address Address { get; set;} } [ProtoContract] public class Address { [ProtoMember(1)] public string Line1 {get;set;} [ProtoMember(2)] public string Line2 {get;set;} }
上面介绍的用来序列化的类的属性都要标记成ProtoContractAttribute,默认情况下,Protobuf-net希望我们通过属性标记对象。
用ProtoContractAttribute 标记的每一个用来序列化的属性都必须是唯一的整数型,这些标识符是用来序列化的,而不是属性名本身,所以如果你想要修改属性名不必要去修改序列号,线上项目最好不好随便改序列号以及属性的类型,尤其是用作缓存或持久化时候,必要时可以往后添加。由于这个值是用来序列化的所以数字越小越好,太大将会占用不必要的空间。
序列化/反序列化
当我们定义好对象我们就可以开始序列化数据了
using (var fs = File.Create("test.bin")) { Serializer.Serialize(fs, person); } 反序列化的代码如下 Person serlizedPerson; using (var fs = File.OpenRead("test.bin")) { Person person = Serializer.Deserialize<Person>(fs); // do something with person }
不使用标签
像前面提到的,我们可以不使用标签来序列化对象,这种情况我们需要通过代码来设置元数据
public class Person { public int Id { get; set; } public string Name { get; set; } public Address Address { get; set;} } public class Address { public string Line1 {get;set;} public string Line2 {get;set;} }
序列化和反序列化代码如下
var personMetaType = RuntimeTypeModel.Default.Add(typeof (Person), false); personMetaType.Add(1, "Id"); personMetaType.Add(2, "Name"); personMetaType.Add(3, "Address"); var addressMetaType = RuntimeTypeModel.Default.Add(typeof(Address), false); addressMetaType.Add(1, "Line1"); addressMetaType.Add(2, "Line2");
我们需要使用整数和属性名来注册,RuntimeTypeModel.Default用来设置类型和属性配置的详细信息。
继承
像其他SOAP序列化一样,当我们派生出一个新类的时候,我们需要在基类上标识序列化程序期望的类型,下面的例子我们增加了派生类`
ProtoContract] public class Male : Person { } [ProtoContract] public class Female : Person { }
我们需要修改Preson如下
ProtoContract] [ProtoInclude(10, typeof(Male))] [ProtoInclude(11, typeof(Female))] public class Person { // properties }
注意:10和11是全局唯一的标识,其他的ProtoIncludeAttribute 和 该类的 ProtoMemberAttribute中都不能再出现该标识符。(ProtoMemberAttribute中出现好像也没影响,项目中亲测)
如果不使用标签,我们需要使用AddSubType 添加到前面定义的personMetaType 中,所以我们需要添加如下代码
// previous metadata configuration personMetaType.AddSubType(10, typeof (Male)); personMetaType.AddSubType(11, typeof(Female)); // and now add the new types RuntimeTypeModel.Default.Add(typeof(Male), false); RuntimeTypeModel.Default.Add(typeof(Female), false);