我将我的项目翻译为使用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-Net ProtoInclude Generic Type Subclass 我们必须使用钩子Serializer.Merge / Serialize;
假设我们有课程:
[Serializable]
[ProtoContract]
public class Anchor : ISerializable
{
[ProtoMember(1)]
public int id;
[ProtoMember(2)]
public Ship ship;
...
}
Serializer.Merge(info,this); 必须添加到构造函数 Anchor(SerializationInfo info,StreamingContext context)
和 Serializer.Serialize(info,this); 添加到 void GetObjectData(SerializationInfo info,StreamingContext context)
所以,我们有:
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);
}
问题: 它是否正确? (“info”被Serializer覆盖?即binaryformatter无法正常工作?在目前的时间点我只是尝试使用protobuf-net而我宁愿让binaryformatter也能正常工作)
2。关于使用ProtoInclude和RuntimeTypeModel.Default
假设我们有类Message ,它是类的基础:类Ack,类HandshakeClientInfo ...类命令。 如果我们想要序列化Message的孩子,请阅读:protobuf-net's [ProtoInclude(1, "MyClass")] did not work 如果我们在编译时知道子类型,我们应该使用ProtoInclude(“告诉”基类:类消息关于它的子节点) - 这没关系。
对于那些我们无法在编译时确定的类型的孩子(因为它在另一个项目中),我们应该使用 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;
...
}
我使用protobuf-net v2(r580)和 RuntimeTypeModel.Default [typeof(Message)]的变体.AddSubType(207,typeof(Command)); 似乎更可取。
问题: 但我不明白它应该放在代码中的哪个位置?在构造函数或....? 是否允许一起使用 ProtoInclude 和 RuntimeTypeModel.Default ?
答案 0 :(得分:5)
首先,我需要明确说明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-net; protobuf-net将序列化对象(和任何子数据),并将数据存储在单个字段中;在反序列化期间,它将扭转这一局面。 ISerializable
接口不用于向protobuf-net添加其他信息。在大多数情况下,如果您想单独支持protobuf-net 和 BinaryFormatter
,那么就不会有Serializer
/ protobuf-net代码构造函数/ GetObjectData
,您也不需要对已经(或不存在)的任何现有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;