我将我的项目翻译为使用protobuf-net而不是BinaryFormatter。看起来缺少文档http://code.google.com/p/protobuf-net/w/list我还查阅了一些来自http://code.google.com/p/protobuf-net/source/browse/但有些事情对我来说仍然不清楚,这就是为什么我决定在这里问:
1.关于ISerializable和Serializer.Merge/Serialize
如果我们有来自ISerializable的继承来进行特定的序列化。正如我读到的:ProtoBuf-NetProtoInclude泛型类型子类我们必须使用钩子Serializer.Merge/Serialize;
假设我们有类:
[Serializable]
[ProtoContract]
public class Anchor : ISerializable
{
[ProtoMember(1)]
public int id;
[ProtoMember(2)]
public Ship ship;
...
}
序列化程序Merge(info,this)必须添加到构造函数锚点(SerializationInfo信息,StreamingContext上下文)
和Serializer.Serialize(info,this)添加到void GetObjectData(SerializationInfo信息,StreamingContext上下文)
因此,我们有:
protected Anchor(SerializationInfo info, StreamingContext context)
{
//for binaryformatter:
Type myType = typeof(Anchor);
foreach (SerializationEntry e in info)
{
FieldInfo f = myType.GetField(e.Name,BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Public|BindingFlags.Instance);
f.SetValue(this,e.Value);
}
//added for protobuf-net:
Serializer.Merge(info, this);
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
//for binaryformatter:
foreach (FieldInfo f in typeof(Anchor).GetFields(BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance))
{
if ((f.Attributes&FieldAttributes.NotSerialized)==0)
info.AddValue(f.Name,f.GetValue(this));
}
//added for protobuf-net:
Serializer.Serialize(info, this);
}
问题:这是正确的吗?("信息"被序列化程序覆盖?即二进制格式化程序将无法正常工作?在当前时间点,我只是尝试使用protobuf-net,我更希望二进制格式化程序也能正常工作)
2.关于使用ProtoInclude和RuntimeTypeModel。默认
假设我们有类Message,它是类的基础:class Ack,class HandshakeClientInfo。。。class命令。如果我们想序列化Message的子级,正如我从protobuf-net';s[ProtoInclude(1,"MyClass")]不起作用我们应该使用ProtoInclude("告诉"基类:class消息关于它的子级),以防我们在编译时知道子级类型-没关系。
对于那些我们在编译时无法确定类型的子类(因为它在另一个项目中),我们应该使用RuntimeTypeModel.Default[typeof(Message)].AddSubType(207,typeof(Command))或使用Type.AssemblyQualifiedName:[ProtoInclude(207,"Trainer.Commands.Command,Simulator,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null")]
[Serializable]
[ProtoContract]
[ProtoInclude(200, typeof(Ack))]
[ProtoInclude(201, typeof(HandshakeClientInfo))]
[ProtoInclude(202, typeof(HandshakeReadyToSimulation))]
[ProtoInclude(203, typeof(FileMessage))]
[ProtoInclude(204, typeof(HandshakeResponse))]
[ProtoInclude(205, typeof(Sync))]
[ProtoInclude(206, typeof(HandshakeSimulationStart))]
public abstract class Message {
[ProtoMember(1)]
public byte Sender;
...
}
i使用protobuf net v2(r580)和RuntimeTypeModel.Default[typeof(Message)].AddSubType(207,typeof(Command))的变体似乎更可取。
问题:但我不明白它应该放在代码中的什么位置?在构造函数中或?是否允许同时使用ProtoInclude和RuntimeTypeModel.Default?
首先,我需要非常清楚protobuf-net和ISerializable
之间的关系。首先,ISerializable
仅由BinaryFormatter
使用。protobuf-net永远不会寻找这个接口,也永远不会直接使用这个接口。所以,你可能会问,为什么protobuf-net会提到这一点?
答:因为有些人有使用BinaryFormatter
所必需的现有代码,但希望在内部使用其他代码。一个很好的例子可能是使用远程处理的现有代码。在这里,protobuf-net可以使用来实现ISerializable
,本质上取代了BinaryFormatter
的内脏。典型用法如下:
protected Anchor(SerializationInfo info, StreamingContext context)
{
Serializer.Merge(info, this);
}
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
Serializer.Serialize(info, this);
}
然后在内部使用protobuf网络;protobuf-net将序列化对象(以及任何子数据),并将数据存储在单个字段中;在反序列化过程中,它将逆转这种情况。ISerializable
接口不用于向protobuf网络添加附加信息。在大多数情况下,如果您想分别支持protobuf-net和BinaryFormatter
,那么构造函数/GetObjectData
中就没有Serializer
/protobuf-net代码,也不需要对您已经(或没有)的任何现有ISerializable
实现进行任何更改。这仅适用于非常特定的场景,在该场景中,您希望从内部更改BinaryFormatter
的工作方式。在这种情况下,您通常会将完全控制权交给protobuf-net。
关于子类型的问题;是的,您可以将[ProtoInclude]
与RuntimeTypeModel.Default
结合使用。基本上,默认情况下(可以调整),protobuf-net第一次看到类型时,会检查属性。如果有,它将使用这些属性来配置模型。但是,您仍然可以对配置进行任何需要的更改,直到必须序列化/反序列化该类型,此时它将配置信息烘焙为执行工作的策略。一旦它决定了一个策略,它就不喜欢你改变配置。
因此,配置您的模型的最佳时间是:在应用程序启动时。或者至少,在你开始做任何有趣的事情之前。为了完整性,我应该注意,如果您想完全手动配置模型,您也可以要求它忽略属性(这种情况非常罕见)。
所以你的线路:
RuntimeTypeModel.Default[typeof(Message)].AddSubType(207, typeof(Command));
在应用程序启动时就可以了。
在某些(罕见的)情况下,您可能会在很久以后发现新的类型。由于各种非常复杂的原因,在开始序列化后允许对现有模型进行更改不是很实际,但是:RuntimeTypeModel.Default
只是一个默认实例。在一些更高级的场景中,可能想要做的是维护自己的模型,然后根据需要配置一个新的知识更丰富的模型。因此,您可以不使用RuntimeTypeModel.Default
,而使用:
static RuntimeTypeModel serializer = TypeModel.Create();
稍后,您可以配置一个新的设置:
var workInProgress = TypeModel.Create();
// TODO: add whatever you need here
serializer = workInProgress;