嵌套 类 的 Protobuf-net 错误:'Type is not expected, and no contract can be inferred: ...'

Protobuf-net error with nested classes: 'Type is not expected, and no contract can be inferred: ...'

我正在使用 Protobuf-net v2.4.4 序列化一系列包含大型双精度数组的嵌套 classes。除了自定义 classes 之外,所有数据类型都是原语或 arrays/lists 原语,例如字符串或 double[],我不确定为什么会收到此错误。对于我的 classes,该错误似乎也会随机弹出。 class 序列化良好 - 重启后,它停止工作并抛出上述错误。我还能够在一个新项目中序列化一个 class,但在我的原始项目中却没有。 有什么好的方法可以调试它并找到它的来源吗?我怀疑这是某种项目设置或冲突的 DLL,因为新项目显然有更少的引用。

我开始单独序列化每个自定义 class 以找出问题所在,但鉴于上述经验,我不确定这是否可靠。不过,我在下面粘贴了我的代码的简化示例。 类 有问题的是 MyClass2 -> MyClass5 和 MyClass3。但是后来我在这些 classes 中看不出任何异常。

如有任何建议,我们将不胜感激。

[ProtoContract] public class MyParentClass
{
    [DataMember] [ProtoMember(1)] public MyClass1 Settings { get; set; } // On its own this class serializes fine
    [DataMember] [ProtoMember(2, OverwriteList = true)] public List<MyClass2> Zones { get; set; } = new List<MyClass2>(); // ProtoBuf does not like this class
    ...
    [DataMember]  [ProtoMember(4)]  public MyClass3 Results { get; set; } // This serializes fine in one project but not in conjunction with the rest here
}

[ProtoContract]  public class MyClass2
{
    [DataMember] [ProtoMember(5)] public MyClass4 Settings { get; set; } // On its own this class serializes fine
    [DataMember] [ProtoMember(6, OverwriteList = true)] public List<MyClass5> faces { get; set; } = new List<MyClass5>(); // ProtoBuf does not like this one
    [DataMember] [ProtoMember(7)] public MyClass6 Result { get; set; } // This class looks similar to MyClass3
    ...
}
[ProtoContract] public class MyClass5
{
    [DataMember] [ProtoMember(4)] public Enum1 Bcond { get; set; } = Enum1._UNSET_; // These enums are also decorated with ProtoContract and ProtoEnum
    ...
    [DataMember] [ProtoMember(7)] public string Twin { get; set; } = "";
    ...
}
[ProtoContract] public class MyClass3
{
    [DataMember] [ProtoMember(1)] public double energy { get; set; }
    ...
    [DataMember] [ProtoMember(3, OverwriteList = true)] public double[] MoreEnergy { get; set; } = new double[8760];
    ...
    [DataMember] [ProtoMember(17, OverwriteList = true)] public double[] EvenMoreDataButNotSetAutomatically { get; set; }
}

从根本上说,我无法让它重现您所看到的;使用上面的代码并在本地使用它,它就可以了。

但是!如果您同时开始序列化类型,可能会出现一些奇怪的计时场景——典型的网络服务器等。这里的一个很好的解决方法是确保所有准备工作尽早发生,例如在您的启动代码中您可以做:

Serializer.PrepareSerializer<MyParentClass>();

(也许还有其他一些)


请注意,new double[8760] 在这里不是一个好主意,因为 protobuf-net 将 运行 构造函数 然后交换数组;您可能想推迟它并在您自己的代码中创建它(或者可以使用其他各种技巧)。您可能还想为此使用 "packed" 数组,即

[ProtoMember(3, OverwriteList = true, IsPacked = true)]

MoreEnergy 属性.

在 v3 中 "packed" 编码在适用时默认启用,因此它基本上是选择退出;在 v2.* 中,它是可选的。所以:最好是明确的。