如何序列化继承属性?

时间:2013-05-28 17:05:02

标签: .net protobuf-net

我确实有一个第三方库,它为某些消息传递了一个抽象类,就像这样。

    [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

1 个答案:

答案 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);
}