Inheritance 使用方法:1。ISerializable with Serializer.Merge/Serialize&;2.ProtoInclude与RuntimeTypeModel。默认值?

Inheritance 使用方法:1。ISerializable with Serializer.Merge/Serialize&;2.ProtoInclude与RuntimeTypeModel。默认值?,inheritance,serialization,protocol-buffers,protobuf-net,iserializable,Inheritance,Serialization,Protocol Buffers,Protobuf Net,Iserializable,我将我的项目转换为使用protobuf net而不是BinaryFormatter。 看起来似乎缺少文档 我还查阅了一些例子 但有些事情我还不清楚,这就是为什么我决定在这里问: 1。关于ISerializable和Serializer.合并/序列化 如果我们从ISerializable继承来进行特定的序列化。 当我读到: 我们必须使用钩子序列化程序。Merge/Serialize 假设我们有课: [Serializable] [ProtoContract] public class Anchor

我将我的项目转换为使用protobuf net而不是BinaryFormatter。 看起来似乎缺少文档 我还查阅了一些例子 但有些事情我还不清楚,这就是为什么我决定在这里问:

1。关于ISerializable和Serializer.合并/序列化

如果我们从ISerializable继承来进行特定的序列化。 当我读到: 我们必须使用钩子序列化程序。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);
    }
问题: 这是正确的吗?(一个“信息”被序列化程序覆盖了?即binaryformatter不能正常工作?目前我只是尝试使用protobuf net,我更希望binaryformatter也能正常工作)

2。关于使用ProtoInclude和RuntimeTypeModel.Default

假设我们有类消息作为类的基础:class Ack、class HandshakeClientInfo…class命令。 如果我们想序列化消息的子项,正如我从中读到的: 我们应该使用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”)]

我使用ProtobufNetV2(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
,那么构造函数中就不会有
序列化程序
/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;
var workInProgress = TypeModel.Create();
// TODO: add whatever you need here
serializer = workInProgress;