2013-05-28 4 views
1

У меня есть сторонняя библиотека, которая предоставляет абстрактный класс для обмена сообщениями, например.Как сериализовать унаследованные свойства?

[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, но он выглядит как проигнорированный в моем производном классе.

Я не могу изменить базовый класс, у меня нет исходного кода для сторонней библиотеки.

У меня может быть около 100 производных классов из MessageBase.

Я должен использовать версию десериализации NonGeneric, потому что я знаю тип только во время выполнения.

Как решить мою проблему?

Thx

ответ

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); 
} 
+0

Как я сказал в своем сообщении, я не могу изменить базовый класс, у меня нет исходного кода для него , Но даже в этом случае, если у меня есть 1000 производных классов, я должен добавить 1000 включений? Звучит не очень хорошо для меня. – Eugen

+0

@ Евген, извините, я пропустил эту часть. В этом случае вам нужно будет указать время выполнения - я добавлю пример, когда я нахожусь на ПК (на мобильном телефоне прямо сейчас), но чтобы подчеркнуть: да, это (настройка отношения между базой и производной от базы) является правильным - и это именно то, что вам нужно будет сделать для любой подобной категории («на основе контракта») сериализатора, включая XmlSerializer и DataContractSerializer. Если я могу утверждать: главный вопрос заключается в том, почему вам нужно 1000 подклассов. Это звучит необычно высоко (он все равно должен справиться, хотя) –

+0

о, человек, который действительно сосет. Я переключился на прото через JSON, чтобы набирать скорость, и вместо этого набрал проблемы. Никогда не возникало таких проблем с json-сериализаторами, они каким-то образом знают обо всех свойствах данного типа, включая базовые классы форм. так или иначе, THX для уточнения, я должен переключиться на другой сериализатор сейчас. Мне нужно 1000 классов, просто чтобы сделать разговор между сервером tcp/client очень безопасным. Поэтому у меня есть класс сообщений для любого типа запроса/ответа. – Eugen

Смежные вопросы