如何使用: 1. ISerializable with Serializer.Merge/Serialize & 2.ProtoInclude with RuntimeTypeModel.Defaul



我将我的项目翻译为使用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))的变体似乎更可取。

问题:但我不明白它应该放在代码中的什么位置?在构造函数中或?是否允许同时使用ProtoIncludeRuntimeTypeModel.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-netBinaryFormatter,那么构造函数/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;

相关内容

  • 没有找到相关文章

最新更新