反序列化属性以抽象基础引用

时间:2012-07-25 19:49:07

标签: c# protobuf-net

是否可以将具有属性的聚合类型反序列化为作为引用的抽象基类型,请参阅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 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)634行+ 0x14字节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)第78行+ 0x5a字节C#

1 个答案:

答案 0 :(得分:2)

感谢您的出色表现;不知道我怎么忽略了这一点。基本上,它归结为密钥跟踪,这在循环图中变得特别复杂。为了尽快获得密钥注册,使用做的是(对于新对象):

  • 创建对象的实例
  • 将其注册到已知密钥
  • 将有效负载反序列化为新创建的对象

显然,在继承的情况下,第一步是错误,无论是否基本类型是抽象/不可创建的。它现在做的是:

  • 针对已知密钥
  • 注册虚拟(不可获取)值
  • null
  • 开始反序列化有效负载
  • 在创建对象时捕获对象(更新虚拟对象)(此代码几乎已经存在,尽管它专门用于“根对象”场景;现在更加通用)

这样做的结果是:它现在有效;您的测试通过,对象的类型正确:

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

需要修订版556或更高版本。