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(object value, ProtoBuf.ProtoReader source, int key, System.Type type, ProtoBuf.BclHelpers.NetObjectOptions options) Line 428 + 0xda bytes C# protobuf-net.dll!ProtoBuf.Serializers .NetObjectSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 45 + 0x9f bytes C# protobuf-net.dll!ProtoBuf.Serializers.TagDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 66 + 0x18 bytes C# protobuf-net .dll!ProtoBuf.Serializers.PropertyDecorator.Read(object value, ProtoBuf.ProtoReader source) Line 74 + 0x18 bytes C# protobuf-net.dll!ProtoBuf.Serializers.TypeSerializer.Read(object value, ProtoBuf.ProtoReader source) Line 205 + 0xf 字节 C# protobuf-net.dll!ProtoBuf.Meta.RuntimeTypeModel.Deserialize(int key, object value, ProtoBuf.ProtoReader source) Line 562 + 0xf bytes C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoBuf.ProtoReader reader, System.Type type, object value, bool noAutoCreate) Line 634 + 0x14 bytes C# protobuf-net.dll !ProtoBuf.Meta.TypeModel.Deserialize(System.IO.Stream source, object value, System.Type type, ProtoBuf.SerializationContext context) Line 555 + 0x14 bytes C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System .IO.Stream source, object value, System.Type type) Line 534 + 0x13 bytes C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream source) Line 78 + 0x5a bytes C#Meta.TypeModel.Deserialize(System.IO.Stream source, object value, System.Type type, ProtoBuf.SerializationContext context) Line 555 + 0x14 bytes C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO. Stream source, object value, System.Type type) Line 534 + 0x13 bytes C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream source) Line 78 + 0x5a bytes C#Meta.TypeModel.Deserialize(System.IO.Stream source, object value, System.Type type, ProtoBuf.SerializationContext context) Line 555 + 0x14 bytes C# protobuf-net.dll!ProtoBuf.Meta.TypeModel.Deserialize(System.IO. Stream source, object value, System.Type type) Line 534 + 0x13 bytes C# protobuf-net.dll!ProtoBuf.Serializer.Deserialize(System.IO.Stream source) Line 78 + 0x5a bytes 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 回答