Reputation: 167
Is it possible to deserialize an aggregate type that has a property to an abstract base type that is a reference, see Aggregate.Base? If not, what is the best workaround?
[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);
}
}
}
Call stack at the point the exception is raised:
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 bytes 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#
Upvotes: 2
Views: 929
Reputation: 1064324
Thank you for an excellent scenario; not sure how I overlooked that. Basically, it comes down to key tracking, which gets particularly complex during cyclic graphs. In order to get the key registered ASAP, what it used to do was (for new objects):
Obviously the first step is an error in the case of inheritance, regardless of whether the base-type is abstract / non-creatable. What it does now is:
null
The upshot of this is: it now works; your test passes, and the object is of the correct type:
var obj = Serializer.Deserialize<Aggregate>(stream);
Assert.AreEqual(typeof(Derived), obj.Base.GetType());
Needs revision 556 or later.
Upvotes: 2