2

参照である抽象基本型へのプロパティを持つ集約型を逆シリアル化することは可能ですか? Aggregate.Base を参照してください。そうでない場合、最善の回避策は何ですか?

[ProtoContract]
[ProtoInclude(1, typeof(Derived))]
public abstract class Base { }

[ProtoContract]
public class Derived : Base
{
    [ProtoMember(1)]
    public int SomeProperty { get; set; }
}

[ProtoContract]
public class Aggregate
{
    [ProtoMember(1, AsReference = true)]
    public Base Base { get; set; }
}

[TestClass]
public class UnitTest
{
    [TestMethod]
    public void TestMethod1()
    {
        var value = new Aggregate { Base = new Derived() };
        using (var stream = new MemoryStream())
        {
            Serializer.Serialize(stream, value);
            stream.Position = 0;

            // Raises an exception
            // Unable to create type Sage.Estimating.Data.Base: Cannot create an abstract class.
            Serializer.Deserialize<Aggregate>(stream);
        }
    }
}

例外が発生した時点でのコール スタック:

protobuf-net.dll!ProtoBuf.BclHelpers.ReadNetObject(オブジェクト値、ProtoBuf.ProtoReader ソース、int キー、System.Type 型、ProtoBuf.BclHelpers.NetObjectOptions オプション) 428 行目 + 0xda バイト C# protobuf-net.dll!ProtoBuf.Serializers .NetObjectSerializer.Read(オブジェクト値、ProtoBuf.ProtoReader ソース) 45 行 + 0x9f バイト C# protobuf-net.dll!ProtoBuf.Serializers.TagDecorator.Read(オブジェクト値、ProtoBuf.ProtoReader ソース) 66 行 + 0x18 バイト C# protobuf-net .dll!ProtoBuf.Serializers.PropertyDecorator.Read(オブジェクト値、ProtoBuf.ProtoReader ソース) 74 行目 + 0x18 バイト C# protobuf-net.dll!ProtoBuf.Serializers.TypeSerializer.Read(オブジェクト値、ProtoBuf.ProtoReader ソース) 205 行目 + 0xf バイト C# protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Deserialize(int キー、オブジェクト値、ProtoBuf.ProtoReader ソース) 562 行 + 0x14 バイト C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoBuf.ProtoReader リーダー、System.Type タイプ、オブジェクト値、bool noAutoCreate) 634 行 + 0x14 バイト C# protobuf-net.dll !ProtoBuf.Meta.TypeModel.Deserialize(System.IO.Stream ソース、オブジェクト値、System.Type タイプ、ProtoBuf.SerializationContext コンテキスト) 555 行 + 0x14 バイト C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System .IO.Stream ソース、オブジェクト値、System.Type タイプ) 534 行 + 0x13 バイト C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream ソース) 78 行 + 0x5a バイト C#Meta.TypeModel.Deserialize(System.IO.Stream ソース、オブジェクト値、System.Type タイプ、ProtoBuf.SerializationContext コンテキスト) 555 行 + 0x14 バイト C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO.ストリーム ソース、オブジェクト値、System.Type タイプ) 534 行 + 0x13 バイト C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream ソース) 78 行 + 0x5a バイト C#Meta.TypeModel.Deserialize(System.IO.Stream ソース、オブジェクト値、System.Type タイプ、ProtoBuf.SerializationContext コンテキスト) 555 行 + 0x14 バイト C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO.ストリーム ソース、オブジェクト値、System.Type タイプ) 534 行 + 0x13 バイト C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream ソース) 78 行 + 0x5a バイト C#

4

1 に答える 1

2

すばらしいシナリオをありがとう。どうやってそれを見落としたのかわからない。基本的には、重要な追跡に帰着します。これは、循環グラフでは特に複雑になります。できるだけ早く登録されたキーを取得するために、以前は(新しいオブジェクトの場合)次のことを行っていました

  • オブジェクトのインスタンスを作成する
  • 既知のキーに対して登録します
  • ペイロードを新しく作成されたオブジェクトに逆シリアル化します

明らかに、基本型が抽象的/作成不可能であるかどうかに関係なく、継承の場合、最初のステップはエラーです。それが今何をするかは次のとおりです。

  • 既知のキーに対してダミーの (取得できない) 値を登録する
  • から始まるペイロードを逆シリアル化しますnull
  • 作成時にオブジェクトをトラップします (ダミーを更新します) (このコードは、「ルート オブジェクト」シナリオ用に特化されていましたが、ほとんど既に存在していましたが、現在はより一般的なものになっています)

これの結果は次のとおりです。テストに合格し、オブジェクトは正しいタイプです:

var obj = Serializer.Deserialize<Aggregate>(stream);
Assert.AreEqual(typeof(Derived), obj.Base.GetType());

リビジョン 556 以降が必要です。

于 2012-07-27T11:30:43.873 に答える