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)); 似乎更可取.
问题: 但我不明白它应该放在代码中的哪个位置?在构造函数或....?是否允许将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);
}
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)
归档时间: |
|
查看次数: |
1083 次 |
最近记录: |