【问题标题】:protobuf-net inheritance : derived class hides base class propertyprotobuf-net 继承:派生类隐藏基类属性
【发布时间】:2016-11-08 07:13:13
【问题描述】:

protobuf-net proto2 c#

我有一个派生类,它通过隐藏相应的同名基类属性来重新定义类型。

我希望序列化一个基类实例并反序列化为派生类型:

[ProtoBuf.ProtoContract(Name=@"BaseClassProto")]
[ProtoBuf.ProtoInclude(typeof(DerivedClass), 1000)]
public partial class BaseClass {
  [ProtoBuf.ProtoMember(1, IsRequired = false, Name = @"MyProperty", DataFormat = ProtoBuf.DataFormat.TwosComplement)] 
  public int MyProperty { get; set; }
}

[ProtoBuf.ProtoContract(Name=@"DerivedClassProto")] 
public partial class DerivedClass : BaseClass {
  [ProtoBuf.ProtoMember(1, IsRequired = false, Name = @"MyProperty", DataFormat = ProtoBuf.DataFormat.TwosComplement)] 
  public new MyEnum MyProperty { get; set; }
  }
}

public class Test {
  var baseObject = new BaseClass{ TestString = "TestBaseObject", TestInt = 1 };

  DerivedClass derivedObject;
  using (var stream = new MemoryStream())
  {
    ProtoBuf.Serializer.Serialize(stream, baseObject);
    Debug.WriteLine(stream.Length);
    stream.Seek(0, SeekOrigin.Begin);
    derivedObject = ProtoBuf.Serializer.Deserialize<DerivedClass>(stream);
  }
}

“System.InvalidCastException”类型的异常发生在 protobuf-net.dll 但未在用户代码中处理 附加信息:无法转换类型的对象 'BaseClass' 输入 'DerivedClass'。

为什么protobuf-net 试图将BaseClass 转换为DerivedClass

protobuf-net 不应该按照DerivedClass 中的原始注释将消息直接反序列化到DerivedClass 吗?

隐藏BaseClass.IntProperty 是否也会隐藏其ProtoMember 注释?从而允许proto index 1DerivedClass 中重新定义?

编辑以添加其他信息:

尝试最小可行的测试用例,即使我重新定义DerivedClass 尽可能简单:

[ProtoBuf.ProtoContract(Name=@"DerivedClassProto")] 
public partial class DerivedClass : BaseClass {
}

我仍然发现 serialize BaseClass / deserialize DerivedClass 抛出相同的 System.InvalidCastException

如果我反序列化为object 类型的引用(而不是DerivedClass),则基础类型为BaseClass。这解释了强制转换异常,但提出了一个问题,为什么 ProtoBuf.Serializer.Deserialize&lt;DerivedClass&gt;() 反序列化为 BaseClass 类型的对象?

【问题讨论】:

    标签: c# inheritance overriding virtual protobuf-net


    【解决方案1】:

    protobuf-net 中不同层次的层次结构是 .proto 术语中的单独消息。子类的标签独立于基类中的标签。重用标签不是级别之间的概念。我很惊讶显示的代码实际上完全有效,因为这似乎在一个级别中使用了两次标记 1(一次用于子类型,一次用于属性 - 都在 MyBaseType 上)。这可能会导致令人困惑的错误。

    【讨论】:

    • 啊,这是一个错字:我已编辑为 [ProtoBuf.ProtoInclude(typeof(MyDerivedType), 1000)]
    • 我的理解是 protobuf-net 默认情况下不会自动将那些在基类中定义的 [ProtoMember] 字段添加到子类消息协定中——但是,如果基类中定义,它将添加它们用[ProtoInclude] 装饰——这是正确的吗?
    • @BaltoStar 在这种情况下,我怀疑是库中的反射错误。重新宣布的成员是用于反思的皇家 PITA。如果第二个成员的名称不同,还会发生这种情况吗?
    • @Balto 从 protobuf-net 的角度来看,基本类型和子类型是完全分开的。即使定义了继承,它也不会将它们添加到子类型的合同中。基类型担心基类型中的东西。子类型关心子类型中的东西。
    • 好吧,如果base-type和sub-type合约是分别单独从base-class和sub-class确定的,那么[ProtoInclude]的目的是什么?