【问题标题】:protobuf - serialization using protobuf-net with inheritanceprotobuf - 使用带有继承的 protobuf-net 进行序列化
【发布时间】:2021-07-10 16:11:57
【问题描述】:

序列化时获取“意外的子类型”。

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

我不想在 BaseClass 上使用“ProtoInclude”。 (我所有的类都是通过 nuget 包独立分发的,并且知道基类中断中的子类)

编辑 1 序列化现在正在工作! (感谢马克格雷维尔) 但是,反序列化不是(获取“无法将 BaseClass 类型的对象转换为 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 的说明,我需要使用自定义“模型”而不是“默认”序列化程序。

【问题讨论】:

  • grandChildInstance 声明的 变量 类型是什么? (不是对象/实例类型;变量类型)?
  • 其类型为“grandChildInstance”

标签: c# protobuf-net


【解决方案1】:

这里的错误是AddSubType API 用于链式构建器使用,并有效地返回您传入的相同对象 - 或者具体来说: 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 或任何其他号码。

【讨论】:

  • 感谢@Marc Gravell!我能够序列化。但是,遇到“反序列化”问题。用“EDIT 1”修改了我原来的问题
  • @teeboy re "EDIT 1" - 使用 model.Deserialize,而不是 Serializer.Deserialize - 后者使用 RuntimeTypeModel.Default,而不是您的自定义模型
  • 哈!谢谢你。那行得通..接受你的回答。所以,如果我在断开连接的架构(如 Kafka)中使用“反序列化”,我需要在发布者和订阅者端构建相同的“模型”。给你送咖啡!
  • 从存储和 CPU 使用的角度来看,关于 Bson 与 Protobuf 序列化/反序列化的任何输入?
  • @teeboy 太棒了,谢谢; re protobuf Vs bson - 取决于有效载荷,但两者都很好
猜你喜欢
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-16
  • 2012-10-10
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多