Я пытаюсь перенести существующий код, который использует XmlSerializer, в protobuf-net из-за повышенной производительности, которую он предлагает, однако у меня возникают проблемы с этим конкретным случаем.
У меня есть объект [], который включает в себя параметры, которые будут отправлены на удаленный хост (своего рода специальное средство мини-RPC). Я знаю набор типов, из которых могут быть эти параметры, но не могу заранее сказать, в каком порядке они будут отправляться. У меня есть три ограничения. Во-первых, я работаю в Compact Framework, поэтому мне нужно что-то, что там работает. Во-вторых, как я уже упоминал, производительность является большой проблемой (со стороны сериализации), поэтому я бы предпочел по возможности избегать использования большого количества отражений. И самое главное, что меня волнует порядок, в котором эти параметры были отправлены. Используя XmlSerializer, было легко просто добавить XmlInclude, но для полей, насколько мне известно, в Protobuf-net нет ничего эквивалентного. Итак, есть ли способ сделать это? Вот упрощенный пример.
[Serializable]
[XmlInclude(typeof(MyType1)),
XmlInclude(typeof(MyType2)),
XmlInclude(typeof(MyType3))
public class Message()
{
public object[] parameters;
public Message(object[] parms)
{
parameters = parms;
}
}
Message m = new Message(new object[] {MyType1(), 33, "test",
new MyType3(), new MyType3()});
MemoryStream ms = new MemoryStream();
XmlSerializer xml = new XmlSerializer(typeof(Message));
xml.Serialize(ms,xml);
Это будет работать только с XmlSerializer, но если я попытаюсь преобразовать его в protobuf-net, я получу сообщение «Нет кодировки по умолчанию для объекта».
Лучшее, что я придумал, это использовать дженерики и [ProtoInclude], как показано в этом пример. Поскольку у меня могут быть разные типы объектов в массиве, это не совсем так. Я добавил общий список для каждого потенциального типа и свойство с [ProtoIgnore] с типом object[], чтобы добавить и получить их. Я должен использовать отражение при их добавлении (чтобы знать, в какой массив поместить каждый элемент), что нежелательно, и я все еще не могу сохранить порядок, поскольку я просто извлекаю все элементы из каждого списка один за другим и помещаю их в новый массив object[] в свойстве get.
Интересно, есть ли способ сделать это?
Я попробовал то, что Марк предложил ниже, но не смог заставить его работать. Я думаю, что я мог что-то неправильно понять.
Используя код, который вы написали. Я подумал, что должен использовать MessageParam Create для создания объектов MessageParam для добавления в список. Итак, в основном я добавил конструктор в Message следующим образом:
public Message(object[] parms)
{
foreach (object o in parms)
{
parameters.Add(MessageParam.Create(o));
}
}
Но если я это сделаю, я получу «Неожиданный тип, обнаруженный во время сериализации; типы должны быть включены в ProtoIncludeAttribute; найден MessageParam`1, переданный как MessageParam», потому что я предполагаю, что сериализатор ожидает неуниверсальную версию. Я неправильно понял ваше предложение? Если да, то как правильно поступить?
CreateDynamic
, который сделает эту работу за вас. - person Marc Gravell   schedule 21.04.2010