Getting "Unexpected sub type" when serializing.
var model = RuntimeTypeModel.Create();
var baseType = model.Add(typeof(BaseClass), true, CompatibilityLevel.Level300);
var child = baseType.AddSubType(10, typeof(ChildOfBase));
child.AddSubType(20, typeof(GrandChildToBase));
using (var stream = new MemoryStream())
{
model.Serialize(stream, grandChildInstance); //ERROR : Unexpected sub type GrandChildToBase
}
Getting "Unexpected sub type GrandChildToBase" Note: Although, I set CompatLevel to 300, it's defaulting to 200. I am on version 3.0.101
I don't want to use "ProtoInclude" on the BaseClass. (All my classes are distributed independently via nuget packages and having knowledge of child classes in base class breaks that)
EDIT 1 Serialization is working now! (Thanks Marc Gravell) But, deserialization is not (Getting "Unable to cast object of type BaseClass to GrandChildToBase")..
var model = RuntimeTypeModel.Create();
model.DefaultCompatibilityLevel = CompatibilityLevel.Level300;
var baseType = model.Add(typeof(BaseClass));
var childType = model.Add(typeof(ChildOfBase));
model.Add(typeof(GrandChildToBase)); // don't need to capture result of this one
baseType.AddSubType(10, typeof(ChildOfBase));
childType.AddSubType(20, typeof(GrandChildToBase));
byte[] result = null;
using (var stream = new MemoryStream())
{
GrandChildToBase grandChildInstance = new();
model.Serialize(stream, grandChildInstance);
result = stream.ToArray();
}
using (var stream = new MemoryStream(result))
{
var payloadObj = Serializer.Deserialize<GrandChildToBase>(stream); ***//ERROR: "Unable to cast object of type BaseClass to GrandChildToBase"***
}
EDIT 2 Per @Marc Gravell's clarification, I need to use the custom "model" and not the "default" serializer.
The error here is that the AddSubType
API is intended for chained builder usage, and effectively returns the same object you passed in - or specifically: the result of AddSubType
is not the MetaType
representing the sub-type; you can see this via:
var child = baseType.AddSubType(10, typeof(ChildOfBase));
Console.WriteLine(ReferenceEquals(child, baseType)); // outputs True
This means that when you then do
child.AddSubType(20, typeof(GrandChildToBase));
you're effectively adding GrandChildToBase
to BaseClass
, not to ChildOfBase
.
I will acknowledge that the library should have told you about this clearly in the .AddSubType(20, typeof(GrandChildToBase))
step! I'll check to see whether we can add an assertion there.
However! To fix the code:
var model = RuntimeTypeModel.Create();
model.DefaultCompatibilityLevel = CompatibilityLevel.Level300;
var baseType = model.Add(typeof(BaseClass));
var childType = model.Add(typeof(ChildOfBase));
model.Add(typeof(GrandChildToBase)); // don't need to capture result of this one
baseType.AddSubType(10, typeof(ChildOfBase));
childType.AddSubType(20, typeof(GrandChildToBase));
using (var stream = new MemoryStream())
{
GrandChildToBase grandChildInstance = new();
model.Serialize(stream, grandChildInstance); //ERROR : Unexpected sub type GrandChildToBase
}
As a side note: the 10
vs 20
- these are not in conflict with each-other, as they are applied (now) at different levels in the hierarchy; they could both be 10
or any other number if you like.