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);
posted @ 2022-11-16 11:55  zhuweirandy  阅读(546)  评论(0编辑  收藏  举报