5

BinaryFormatter のドロップイン代替として protobuf-net を使用できる実際の例はありますか? それは可能ですか?

実際には、次のような1つのメッセージタイプのシリアライザーが必要です

public class A {
  public B[] Bs { get;set; }
  public C[] Cs { get;set; }
}

すべての型は異なるアセンブリで定義されており、多くのプロパティがあります。クラスAおよびその他の使用されるタイプ(B、C)について、すべてのパブリックプロパティが含まれるプロトコントラクトを自動的に生成するオプションはありますか?

var formatter = ProtoBuf.Serializer.CreateFormatter<A>()

ただ動作しますか?

4

2 に答える 2

7

まず、protobuf-netは、の代わりに100%低下することを意図しておらず、そのように主張していませんBinaryFormatter。機能が少し異なります。

少し振り返ってみませんか?基本的にはのサポートがありImplicitFieldsますが、現在これはを介してのみ利用可能であり[ProtoContract]、を介して便利に行うことはできませんRuntimeTypeModel。これは少し面倒で、私のリストにあります。ただし、暗黙フィールドは少し危険であると考えていることを指摘しておく必要があります。これは、DTO内部が変更されないことがわかっている場合にのみ実行する必要があります。しかし:あなたの質問に答えるために、あなたはあなたが期待するタイプを繰り返し、それらを手動でモデルに追加することができます:

static void Main()
{
    Prepare(typeof(A), typeof(B), typeof(C));
    // if you really want to use IFormatter...
    var formatter = RuntimeTypeModel.Default.CreateFormatter(typeof (A));
    var obj = new A {Bs = new B[] {new B()}};
    using (var ms = new MemoryStream())
    {
        formatter.Serialize(ms, obj);
        ms.Position = 0;
        var clone = formatter.Deserialize(ms);
    }
}
static void Prepare(params Type[] types)
{
    if(types != null) foreach(var type in types) Prepare(type);
}
static void Prepare(Type type)
{
    if(type != null && !RuntimeTypeModel.Default.IsDefined(type))
    {
        Debug.WriteLine("Preparing: " + type.FullName);
        // note this has no defined sort, so invent one
        var props = type.GetProperties(); 
        Array.Sort(props, (x, y) => string.Compare(
            x.Name, y.Name, StringComparison.Ordinal));
        var meta = RuntimeTypeModel.Default.Add(type, false);
        int fieldNum = 1;
        for(int i = 0 ; i < props.Length ; i++)
        {
            meta.Add(fieldNum++, props[i].Name);
        }

    }
}

ここでの使用IFormatterは完全に不要であることに注意してください。RuntimeTypeModel.Default.Serialize(...)またはを使用することもできますSerializer.Serialize<T>(...)

脚注として:モデルをもっと定義することをお勧めします...繰り返します。例えば:

RuntimeTypeModel.Default.Add(typeof(A)).Add("Bs", "Cs");
RuntimeTypeModel.Default.Add(typeof(B)).Add("Foo");
RuntimeTypeModel.Default.Add(typeof(C)).Add("Bar", "Blap", "Blop");
于 2012-07-19T21:46:46.057 に答える
4

これは、私が使用した Prepare 関数の最終バージョンです。

static void Prepare(params Type[] types)
        {
            foreach (var type in types)
            {
                if (type != null && !RuntimeTypeModel.Default.IsDefined(type))
                {
                    if (type.Namespace.StartsWith("System"))
                        return;

                    Debug.WriteLine("Preparing: " + type.FullName);
                    // note this has no defined sort, so invent one
                    var props = type.GetProperties();
                    Array.Sort(props, (x, y) => string.Compare(
                        x.Name, y.Name, StringComparison.Ordinal));
                    var meta = RuntimeTypeModel.Default.Add(type, false);
                    int fieldNum = 1;
                    for (int i = 0; i < props.Length; i++)
                        if (props[i].CanWrite)
                        {                            
                            meta.Add(fieldNum++, props[i].Name);

                            if (!RuntimeTypeModel.Default.IsDefined(props[i].PropertyType))
                                if (props[i].PropertyType.HasElementType)
                                    Prepare(props[i].PropertyType.GetElementType()); //T[]
                                else if (props[i].PropertyType.IsGenericType)
                                    Prepare(props[i].PropertyType.GetGenericArguments()); //List<T>
                                else
                                    Prepare(props[i].PropertyType);
                        }
                }
            }
        }

誰かが興味を持っている場合、これは私のベンチマークの結果です (シリアライズ + デシリアライズ):

BinaryFormatter      10000 messages: 2.131s  5028 bytes/msg
Json.NET Bson        10000 messages: 1.679s  1071 bytes/msg
MetSys Bson          10000 messages: 1.581s  1035 bytes/msg
Protobuf             10000 messages: 0.145s   109 bytes/msg
MsgPack              10000 messages: 0.844s   106 bytes/msg

ノート:

  • MetSys.Bson ライブラリは、10 進数型をうまく処理できません。
  • MsgPack ライブラリに読み取り専用プロパティの問題がある

助けてくれて、素晴らしいライブラリを提供してくれた Mar に感謝します。

于 2012-07-19T23:04:33.677 に答える