我确实有一个第三方库,它为某些消息传递了一个抽象类,就像这样。
[ProtoContract]
public abstract class MessageBase
{
[ProtoMember(101)]
public string ErrorMessage { get; set; }
public abstract int Type { get; }
}
现在在我的应用程序中,我确实从它创建了一个派生类
[ProtoContract]
[ProtoInclude(999, typeof(MessageBase))]
public class Echo : MessageBase
{
public const int ID = 1;
public override int Type
{
get { return ID; }
}
[ProtoMember(1)]
public string Message { get; set; }
}
但是当我尝试(de)/序列化属性ErrorMessage从基类被忽略。这是模拟情况的代码。
using (MemoryStream ms = new MemoryStream())
{
Echo echo = new Echo{Message = "Some message", ErrorMessage = "XXXXX"};
ProtoBuf.Serializer.Serialize(ms, echo);
//reset ms
ms.Seek(0, SeekOrigin.Begin);
Echo echo1 = (Echo)ProtoBuf.Serializer.NonGeneric.Deserialize(typeof(Echo), ms);
Debug.Assert(echo.ErrorMessage == echo1.ErrorMessage, "Must be the same");
}
我读过ProtoInclude,但看起来在我的派生类中被忽略了。
我无法更改基类,我没有第三方库的源代码。
我可能有大约100个来自MessageBase的派生类。
我必须使用NonGeneric版本的反序列化,因为我只在运行时知道类型。
如何解决我的问题?
THX
答案 0 :(得分:0)
您的ProtoIncludeAttribute放错了地方。需要告知基类型派生类型,而不是相反。
将ProtoIncludeAttribute添加到MessageBase,并将其从子类中删除(除非子类本身有更多子类)
如评论中所述;如果无法编辑基类型,则必须在运行时进行配置。这可以按如下方式完成(另见基于评论中的测试):
[Test]
public void AddSubtypeAtRuntime()
{
var messageBase = RuntimeTypeModel.Default[typeof(MessageBase)];
// this could be explicit in code, or via some external config file
// that you process at startup
messageBase.AddSubType(10, typeof(Echo)); // would need to **reliably** be 10
messageBase.AddSubType(11, typeof(Foo));
messageBase.AddSubType(12, typeof(Bar)); // etc
// test it...
Echo echo = new Echo { Message = "Some message", ErrorMessage = "XXXXX" };
MessageBase echo1;
using (var ms = new MemoryStream())
{
Serializer.NonGeneric.Serialize(ms, echo);
ms.Position = 0;
echo1 = (MessageBase)Serializer.NonGeneric.Deserialize(
typeof(MessageBase), ms);
}
Assert.AreSame(echo.GetType(), echo1.GetType());
Assert.AreEqual(echo.ErrorMessage, echo1.ErrorMessage);
Assert.AreEqual(echo.Message, ((Echo)echo1).Message);
}