I am trying to migrate existing code that uses XmlSerializer to protobuf-net due to the increased performance it offers, however I am having problems with this specific case.
I have an object[] that includes parameters that are going to be sent to a remote host (sort of a custom mini rpc facility). I know the set of types from which these parameters can be, but I cannot tell in advance in which order they are going to be sent.
I have three constraints. The first is that I am running in Compact Framework, so I need something that works there. Second, as I mentioned performance is a big concern (on the serializing side) so I would rather avoid using a lot of reflection there if possible. And the most important is that I care about the order in which this parameters were sent.
Using XmlSerializer it was easy just adding XmlInclude, but for fields there is nothing equivalent as far as I know in Protobuf-net. So, is there a way to do this? Here is a simplified example.
[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);
That will just work with XmlSerializer, but if I try to convert it to protobuf-net I will get a "No default encoding for Object" message.
The best I came up with is to use generics and [ProtoInclude] as seen in this example. Since I can have different object types within the array this doesn't quite make it. I added a generic List for each potential type and a property with [ProtoIgnore] with type object[] to add them and get them. I have to use reflection when adding them (to know in which array to put each item) which is not desirable and I still can't preserve the ordering as I just extract all the items on each list one by one and put them into a new object[] array on the property get.
I wonder if there is a way to accomplish this?
I tried what Marc suggested below, but I couldn't get it to work. I think I may have misunderstood something.
Using the code you wrote. I thought I should use MessageParam Create to generate MessageParam objects to add to the list. So basically I added a constructor to Message like this:
public Message(object[] parms)
{
foreach (object o in parms)
{
parameters.Add(MessageParam.Create(o));
}
}
But, if i do that I will get "Unexpected type found during serialization; types must be included with ProtoIncludeAttribute; found MessageParam`1 passed as MessageParam" because I assume the serializer is expecting the non-generic version. Did I misunderstand your suggestion? If so, what is the right thing to do?
See Question&Answers more detail:
os