我希望能够以保留/嵌入类型信息的方式序列化 IMessage 的具体实例(类似于 Json.NET 中可用的内容),以便在反序列化时可以使用类型信息来实现这些信息具体事例。我很清楚下面的反/序列化方法不起作用。任何关于如何改变它们以便它们发挥作用的指导将不胜感激。
public interface IMessage {}
public interface IEvent : IMessage {}
[ProtoContract]
public class DogBarkedEvent : IEvent {
[ProtoMember(0)]
public string NameOfDog { get; set; }
[ProtoMember(1)]
public int Times { get; set; }
}
//Somewhere in a class far, far away
public byte[] Serialize(IMessage message) {
using(var stream = new MemoryStream()) {
ProtoBuf.Serializer.Serialize<IMessage>(stream, message);
return stream.ToArray();
}
}
public IMessage Deserialize(byte[] data) {
using(var stream = new MemoryStream(data)) {
return ProtoBuf.Serializer.Deserialize<IMessage>(stream);
}
}
阐明一点:序列化事件被写入持久性。阅读它们时,使用带有泛型参数的反序列化方法不是一个可行的选择(最好的方法是将类型信息指定为常规参数或使用通用约定,在本例中为 IMessage)。
I'd like to be able to serialize concrete instances of IMessage in such a way that the type information is retained/embedded (akin to what's available in e.g. Json.NET), so that upon deserialization that type information can be used to materialize those concrete instances. I'm well aware that the de-/serialization methods below don't work. Any guidance would be appreciated on how to change them so they do work.
public interface IMessage {}
public interface IEvent : IMessage {}
[ProtoContract]
public class DogBarkedEvent : IEvent {
[ProtoMember(0)]
public string NameOfDog { get; set; }
[ProtoMember(1)]
public int Times { get; set; }
}
//Somewhere in a class far, far away
public byte[] Serialize(IMessage message) {
using(var stream = new MemoryStream()) {
ProtoBuf.Serializer.Serialize<IMessage>(stream, message);
return stream.ToArray();
}
}
public IMessage Deserialize(byte[] data) {
using(var stream = new MemoryStream(data)) {
return ProtoBuf.Serializer.Deserialize<IMessage>(stream);
}
}
To shed a little light: The serialized events get written to persistence. When reading them, usage of a deserialization method with a generic argument is not a viable option (the best that can be done is specifying the type information as a regular parameter or using the common contract, IMessage in this case).
发布评论
评论(1)
有两种方法可以解决这个问题;我最不首选的选择是使用
DynamicType=true
- 这更昂贵并且限制可移植性/版本控制,但不要求了解数据预先。我的首选选项是为每个接口声明一个固定标识符,使其能够识别数据本身。如下所示。有关信息,
DontAskWrapper
是因为Serialize()
使用GetType()
;这意味着它不会发现接口底座。我怀疑我可以改进这一点,但这适用于今天的 v2:这是没有属性的相同内容:
请注意,在两种情况下,
TypeModel
应该被缓存并重新使用;它是线程安全的,因此可以由不同线程积极并行使用等。There are two ways of approaching this; my least preferred option is to use
DynamicType=true
- this is more expensive and limits portability/versioning, but places no demands on knowing the data up-front. My preferred option is to declare a fixed identifier per interface, allowing it to recognise the data itself. This is shown below.For info,
DontAskWrapper
is becauseSerialize()
usesGetType()
; which means it won't spot the interface base. I suspect I can improve that, but this works for today on v2:And here's the same thing without attributes:
Note that in both cases the
TypeModel
should be cached and re-used; it is thread-safe, so can be aggressively used in parallel by different threads, etc.