使用方法:1.使用Serializer.Merge/Serialize&2进行ISerializable,使用RuntimeTypeModel.Default进行ProtoInclude?

Lon*_*ter 2 inheritance serialization protocol-buffers protobuf-net iserializable

我翻译我的项目使用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;
    ...
 }
Run Code Online (Sandbox Code Playgroud)

Serializer.Merge(信息,这一点); 必须添加到构造函数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);
    }
Run Code Online (Sandbox Code Playgroud)

问题: 这是对的吗?("info"被Serializer覆盖?即binaryformatter无法正常工作?在目前的时间点我只是尝试使用protobuf-net而我宁愿让binaryformatter也能正常工作)

2.关于使用ProtoInclude和RuntimeTypeModel.Default

假设我们有类基于类的消息:类Ack,类HandshakeClientInfo ...类命令.如果我们要序列化Message的子节点,正如我读到的那样:protobuf-net的[ProtoInclude(1,"MyClass")]不起作用 我们应该使用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;
...
}
Run Code Online (Sandbox Code Playgroud)

我使用protobuf-net v2(r580)和变种与RuntimeTypeModel.Default [typeof(Message)].AddSubType(207,typeof(Command)); 似乎更可取.

问题: 但我不明白它应该放在代码中的哪个位置?在构造函数或....?是否允许将ProtoIncludeRuntimeTypeModel.Default一起使用?

Mar*_*ell 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);
}
Run Code Online (Sandbox Code Playgroud)

然后在内部使用protobuf-net; protobuf-net将序列化对象(和任何子数据),并将数据存储在单个字段中; 在反序列化期间,它将扭转这一局面.该ISerializable接口不用于向protobuf-net添加其他信息.在大多数情况下,如果你想单独支持protobuf网 BinaryFormatter,然后就没有Serializer在构造函数//protobuf网代码GetObjectData,而且也不需要进行任何更改任何到任何现有的ISerializable,你已经实现(或不).这仅适用于您希望从内部更改工作方式的特定场景.在这种情况下,您通常会完全控制protobuf-net.BinaryFormatter


关于子类型的问题; 是的,你可以[ProtoInclude]结合使用RuntimeTypeModel.Default.基本上,默认情况下(可以调整),protobuf-net第一次看到一个类型时,它会检查属性.如果有,它将使用这些属性来配置模型.但是,您仍然可以对配置进行任何更改,直到它必须序列化/反序列化该类型,此时它会将配置信息烘焙到执行工作的策略中.一旦决定了策略,它就不喜欢你改变配置.

因此,配置模型的最佳时间是:在应用启动时.或者至少,在你开始做任何有趣的事情之前.为了完整性,我应该注意,如果你想完全手动配置模型,你也可以要求它忽略属性(这是非常罕见的).

你的线路:

RuntimeTypeModel.Default[typeof(Message)].AddSubType(207, typeof(Command));
Run Code Online (Sandbox Code Playgroud)

在app启动会很好.

在某些(罕见)情况下,您可能会在以后发现新类型.由于各种非常复杂的原因,在开始序列化后允许更改现有模型并不是很实际,但是:RuntimeTypeModel.Default只是一个默认实例.在一些更高级的场景中,您可能想要做的是维护自己的模型,然后根据需要配置一个更加知识渊博的新模型.因此,RuntimeTypeModel.Default您可以使用以下方法,而不是使用:

static RuntimeTypeModel serializer = TypeModel.Create();
Run Code Online (Sandbox Code Playgroud)

然后在以后,您可以配置新的设置:

var workInProgress = TypeModel.Create();
// TODO: add whatever you need here
serializer = workInProgress;
Run Code Online (Sandbox Code Playgroud)