4

XmlSerializerを使用する既存のコードをprotobuf-netに移行しようとしていますが、パフォーマンスが向上しているため、この特定のケースで問題が発生しています。

リモートホスト(カスタムミニRPC機能の一種)に送信されるパラメーターを含むobject[]があります。これらのパラメータを使用できるタイプのセットは知っていますが、どの順序で送信されるかを事前に知ることはできません。3つの制約があります。1つ目は、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 []のプロパティを追加して、それらを追加して取得しました。それらを追加するときにリフレクションを使用する必要があります(各アイテムを配置する配列を知るため)。これは望ましくありませんが、各リストのすべてのアイテムを1つずつ抽出して、プロパティgetの新しいobject[]配列。

これを達成する方法があるのだろうか?


マークが以下に提案したことを試しましたが、うまくいきませんでした。何か誤解したのではないかと思います。

作成したコードを使用します。MessageParam Createを使用して、リストに追加するMessageParamオブジェクトを生成する必要があると思いました。したがって、基本的に、次のようにメッセージにコンストラクタを追加しました。

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

しかし、そうすると、シリアライザーが非ジェネリックバージョンを予期していると想定しているため、「シリアル化中に予期しないタイプが見つかりました。タイプはProtoIncludeAttributeに含まれている必要があります。MessageParam`1がMessageParamとして渡されました」というメッセージが表示されます。私はあなたの提案を誤解しましたか?もしそうなら、何をするのが正しいですか?

4

1 に答える 1

4

object問題が発生します。私はもっ​​と次のようなことを試みます:

[ProtoContract]
class Message
{
    private readonly List<MessageParam> parameters = new List<MessageParam>();
    [ProtoMember(1)]
    public List<MessageParam> Parameters { get { return parameters; } }
}
[ProtoContract]
[ProtoInclude(3, typeof(MessageParam<int>))]
[ProtoInclude(4, typeof(MessageParam<float>))]
[ProtoInclude(5, typeof(MessageParam<DateTime>))]
//...known types...
abstract class MessageParam {
    public abstract object UntypedValue { get; set; }
    public static MessageParam<T> Create<T>(T value) {
        return new MessageParam<T> { 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<T> : MessageParam
{
    [ProtoMember(1)]
    public T Value { get; set; }
    public override object UntypedValue
    {
        get { return Value; }
        set { Value = (T)value; }
    }
}

リリースされていない「v2」コードは、属性を介してではなく、実行時に関係を定義するためのはるかに多くの機能を提供することに注意してください(これはここではかなり制限されています)。

于 2010-04-20T22:28:22.413 に答える