在Protobuf-net中,如何在内部传递具有不同类型对象的类型对象数组,事先知道潜在类型的集合

我正在尝试将使用XmlSerializer的现有代码迁移到protobuf-net,因为它提供了更高的性能,但是我遇到了这个特定情况的问题。

我有一个对象[],其中包含将要发送到远程主机的参数(一种自定义的迷你rpc工具)。 我知道这些参数的类型集合,但我无法预先知道它们将以何种顺序发送。 我有三个限制。 首先是我在Compact Framework中运行,所以我需要在那里工作的东西。 其次,正如我所提到的,性能是一个很大的问题(在序列化方面)所以我宁愿避免在可能的情况下使用大量的reflection。 最重要的是我关心这些参数的发送顺序。 使用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,我将得到“没有对象的默认编码”消息。

我想出的最好的是使用generics和[ProtoInclude],如本例所示 。 由于我可以在数组中使用不同的对象类型,因此无法实现。 我为每个潜在类型添加了一个通用List,并为[ProtoIgnore]添加了一个类型为object []的属性来添加它们并获取它们。 添加它们时我必须使用reflection(知道放入每个项目的数组)这是不可取的,我仍然无法保留排序,因为我只是逐个提取每个列表上的所有项目并将它们放入属性get上的new object []数组。

我想知道是否有办法实现这一目标?


我尝试过Marc在下面提出的建议,但我无法让它发挥作用。 我想我可能误解了一些事情。

使用您编写的代码。 我以为我应该使用MessageParam Create生成MessageParam对象以添加到列表中。 所以基本上我向Message添加了一个构造函数,如下所示:

 public Message(object[] parms) { foreach (object o in parms) { parameters.Add(MessageParam.Create(o)); } } 

但是,如果我这样做,我将得到“序列化期间发现的意外类型;类型必须包含在ProtoIncludeAttribute中;发现MessageParam`1作为MessageParam传递”因为我假设序列化程序期望非generics版本。 我误解了你的建议吗? 如果是这样,做什么是正确的?

object将成为问题。 我会尝试更像的东西:

 [ProtoContract] class Message { private readonly List parameters = new List(); [ProtoMember(1)] public List Parameters { get { return parameters; } } } [ProtoContract] [ProtoInclude(3, typeof(MessageParam))] [ProtoInclude(4, typeof(MessageParam))] [ProtoInclude(5, typeof(MessageParam))] //...known types... abstract class MessageParam { public abstract object UntypedValue { get; set; } public static MessageParam Create(T value) { return new MessageParam { Value = value }; } public static MessageParam CreateDynamic(object value) { Type type = value.GetType(); switch (Type.GetTypeCode(value.GetType())) { // special cases case TypeCode.Int32: return Create((int)value); case TypeCode.Single: return Create((float)value); case TypeCode.DateTime: return Create((DateTime)value); // fallback in case we forget to add one, or it isn't a TypeCode default: MessageParam param = (MessageParam)Activator.CreateInstance( typeof(MessageParam<>).MakeGenericType(type)); param.UntypedValue = value; return param; } } } [ProtoContract] sealed class MessageParam : MessageParam { [ProtoMember(1)] public T Value { get; set; } public override object UntypedValue { get { return Value; } set { Value = (T)value; } } } 

请注意,未发布的“v2”代码提供了更多在运行时定义关系的能力,而不是通过属性(这在此非常有限)。