1

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

    [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; }
}

但是当我尝试(反)/序列化基类中的属性 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 的信息,但它看起来在我的派生类中被忽略了。

我无法更改基类,我没有第 3 方库的源代码。

我可能有大约 100 个来自 MessageBase 的派生类。

我必须使用非通用版本的反序列化,因为我只在运行时知道类型。

我该如何解决我的问题?

谢谢

4

1 回答 1

0

您的 ProtoIncludeAttribute 放错了位置。基类型需要被告知派生类型,而不是相反。

Add ProtoIncludeAttribute to MessageBase, and remove it from the subclass (unless of course the subclass itself has more subclasses)


As explained in comments; if the base-type cannot be edited, it must be configured at runtime. That can be done as follows (see also a test based on the one from the comments):

[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);
}
于 2013-05-28T17:11:37.260 回答