这里是example class provided by Marc Gravel的简介,介绍如何使用Protobuf.net:
[ProtoContract]
class Person {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
[ProtoMember(3)]
public Address Address {get;set;}
}
[ProtoContract]
class Address {
[ProtoMember(1)]
public string Line1 {get;set;}
[ProtoMember(2)]
public string Line2 {get;set;}
}
我有一些问题,在搜索网络后找不到答案:
如果在第1天,我知道我不需要名称属性[ProtoMember(2)],那么如果我省略[ProtoMember(2)]属性,Protobut.net将忽略该属性,并且不在输出序列化数据中包括它?如果为true,则在另一端反序列化数据时-Name初始化为什么-null?
让我们说所有3个属性都已如上所述初步序列化。如果将来发现不再需要名称属性[ProtoMember(2)],可以安全地省略[ProtoMember(2)]属性,以便仅对第一个和第三个属性进行序列化吗?如果为true,是否可以仅保留显示的属性编号(即1和3)?如果是这种情况,有什么警告吗?
如果可以为类中的属性省略序列化属性,那么如果反序列化方面的类定义不同步怎么办?例如,假设反序列化类定义了上面的所有3个属性,但是序列化代码仅定义了1和3?同样,如果反序列化代码只希望看到属性1和3,而序列化代码将全部发送3,那么它仍然可以工作还是会产生错误?
答案 0 :(得分:2)
null
(注意:还有一个可以抑制构造函数的选项,在这种情况下,即使您的班级有构造函数/初始化程序,它也会是null
IExtensible
(通常通过子类Extensible
的实现)-如果可以,则意外数据将单独存储,以便仍可以手动查询,或(更常见的)“往返”(即,如果您再次对其进行序列化,则即使您没有想到,也会保留额外的数据)
public bool ShouldSerializeName() => Name != null && SomethingElse == 42;
答案 1 :(得分:1)
由于其他人可能想知道这些问题的答案,所以我决定发布问题并分享我的发现。
这些问题实际上很容易通过测试程序解决:
class Program
{
static void Main(string[] args)
{
var person = new Person1
{
Id = 12345,
Name = "Fred",
Address = new Address
{
Line1 = "Flat 1",
Line2 = "The Meadows"
}
};
//
byte[] arr = Serialize(person);
Person2 newPerson = Deserialize(arr);
/*
using (var file = File.Create("person.bin"))
{
Serializer.Serialize(file, person);
}
//
Person newPerson;
using (var file = File.OpenRead("person.bin"))
{
newPerson = Serializer.Deserialize<Person>(file);
}
*/
}
public static byte[] Serialize(Person1 person)
{
byte[] result;
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, person);
result = stream.ToArray();
}
return result;
}
public static Person2 Deserialize(byte[] tData)
{
using (var ms = new MemoryStream(tData))
{
return Serializer.Deserialize<Person2>(ms);
}
}
}
[ProtoContract]
class Person1
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
[ProtoContract]
class Person2
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
因此,要尝试Protobuf.net在序列化时是否忽略Name属性,请首先在debug中运行代码以查看所有3个属性序列化的字节总数。这可以通过在Serialize(person)行上设置断点并检查arr的大小来完成。
然后,从Person1类的Name属性中删除[ProtoMember(2)]属性。在调试中运行代码表明它已将其排除在外,因为字节数比以前少了6个。然后将该对象反序列化为Person2的对象时,它表明Name属性被初始化为null。
在将Person1类的Name属性替换为[ProtoMember(2)]属性后,请为Person2类删除相同的属性。通过代码调试之后,它表明在反序列化调用之后,Person2.Name属性设置为null。
因此,看起来Protobuf.net经过精心设计,具有很高的灵活性,效率,并且在某些方面向后兼容,因为它支持删除过时的属性。