protobuf - 使用 protobuf-net 继承的序列化

protobuf - serialization using protobuf-net with inheritance

序列化时出现“意外的子类型”。

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
}

获取“意外的子类型 GrandChildToBase” 注意:尽管我将 CompatLevel 设置为 300,但它默认为 200。 我的版本是 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)

编辑 1 序列化现在正在工作! (感谢马克·格拉维尔) 但是,反序列化不是(获取“无法将 BaseClass 类型的 object 转换为 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"***                  
    }

编辑 2 根据@Marc Gravell 的说明,我需要使用自定义“模型”而不是“默认”序列化程序。

这里的错误是 AddSubType API 用于 链式构建器使用 ,实际上 returns 您传入的同一对象 - 或者具体地说:AddSubType 的结果是 而不是 代表子类型的 MetaType;您可以通过以下方式查看:

var child = baseType.AddSubType(10, typeof(ChildOfBase));
Console.WriteLine(ReferenceEquals(child, baseType)); // outputs True

这意味着当你之后做

child.AddSubType(20, typeof(GrandChildToBase));

您实际上是将 GrandChildToBase 添加到 BaseClass,而不是 ChildOfBase

我承认图书馆应该在 .AddSubType(20, typeof(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));
using (var stream = new MemoryStream())
{
    GrandChildToBase grandChildInstance = new();
    model.Serialize(stream, grandChildInstance); //ERROR : Unexpected sub type GrandChildToBase
}

附带说明:1020 - 这些并不相互冲突,因为它们(现在)应用于层次结构的不同级别;如果您愿意,它们都可以是 10 或任何其他数字。