3

私はprotobuf-netの問題に遭遇し、この最も単純なケースに絞り込みました。クラスが同じタイプのプロパティを持つリンクリストタイプの構造が必要です。これをシリアル化すると、うまく機能します。ただし、タイプがクラスではなくインターフェイスの場合、次のエラーが発生します。ConsoleApplication1.foo(ConsoleApplication1.ifoo)のシリアライザーが生成されると、タイプを変更できません。

これは私がこのエラーを生成しなければならないコードです:

class Program
{
    static void Main(string[] args)
    {
        var toSerialize = new foo();
        toSerialize.data = "foo1";

        var subf = new foo();
        subf.data = "foo2";

        toSerialize.subfoo = subf;

        using (var pbfsc = new FileStream("testfile.proto", FileMode.Create))
        {
            using (var cs = new GZipStream(pbfsc, CompressionMode.Compress))
            {
                ProtoBuf.Serializer.Serialize(cs, toSerialize);
            }
            pbfsc.Close();
        }
    }
}

[ProtoContract, ProtoInclude(2000, typeof(foo))]
public interface ifoo
{
    [ProtoMember(1)]
    string data { get; set; }
    [ProtoMember(2)]
    ifoo subfoo { get; set; }
}
[ProtoContract]
public class foo : ifoo
{

    [ProtoMember(1)]
    public string data { get; set; }
    [ProtoMember(2)]
    public ifoo subfoo { get; set; }
}

私はできる限りの主題についてすべての読書をしました、そして、私は私が間違ったことをしたのを見ることができません。インターフェイスのリスト(コードは表示されていません)の問題に似ているように見えるので、オブジェクトをラッパークラスに入れてみましたが、それでも役に立ちませんでした。

subfooをタイプfooに変更すると、正常に機能しますが、より複雑な現実の問題では、インターフェイスの使用に固執したいと思います。ここで何か間違ったことをしたことがありますか、それともこれはprotobuf-netの問題ですか?

どんな助けでも大歓迎です。

乾杯

アレックス

4

1 に答える 1

1

コントラクトであるインターフェイスを実装するときの最上位オブジェクトの処理を改善するために完了する必要がある未解決の作業がいくつかあります。基本的に、現時点ではルート オブジェクトの非インターフェース部分のみを処理しますが、プロパティ/サブオブジェクトなどのインターフェースを処理します。

あなたが見ている例外は少しifoo奇妙です - 私はそれがプロパティのために時間内に知っていると思っていsubfooますが、ここでの根本的な問題は追加することで回避できます:

Serializer.PrepareSerializer<ifoo>();

シリアライゼーション コードの前 (理想的にはかなり早い段階のどこかで、一度だけ呼び出す必要があります)。

ただし、ここでは実際に二重シリアル化していることにも注意してください。プロパティをシリアル化すると、インターフェイス ( )具象型 ( ) の両方ifoo subfooから装飾されたメンバーがシリアル化されます。これらは実際には同じ値であるため、ここには冗長性があります。ifoofoo

メンバーレベルの属性を具象型から取り除いください。ただし、ルートオブジェクトの不具合により、これは少し問題になります。両方の問題を解決する別の修正(不要PrepareSerializer) は次のとおりです。

using ProtoBuf;
using System;
class Program
{
    static void Main(string[] args)
    {
        var root = new foo();
        root.data = "foo1";

        var subf = new foo();
        subf.data = "foo2";

        root.subfoo = subf;
        var toSerialize = new FooRoot { root = root };

        // this does the same as your file-code, but runs
        // both serialize and deserialize - basicaly, it is
        // a lazy way of checking it end-to-end
        var clone = Serializer.DeepClone(toSerialize).root;
        Console.WriteLine(clone.data); // "foo1"
        Console.WriteLine(clone.subfoo.data); // "foo2"
    }
}
[ProtoContract]
public class FooRoot
{
    [ProtoMember(1)]
    public ifoo root { get; set; }
}
[ProtoContract, ProtoInclude(2000, typeof(foo))]
public interface ifoo
{
    [ProtoMember(1)]
    string data { get; set; }
    [ProtoMember(2)]
    ifoo subfoo { get; set; }
}
[ProtoContract]
public class foo : ifoo
{
    public string data { get; set; }
    public ifoo subfoo { get; set; }
}

root-object/interface-support の不具合が解決されると、FooRootラッパーは必要なくなりますが、レガシー サポートのために、おそらく修正を有効/無効にするスイッチを追加する必要があります。

于 2012-09-28T06:32:27.157 に答える