首页 > 解决方案 > 嵌套类的 Protobuf-net 错误:'类型不是预期的,并且无法推断出任何合同:...'

问题描述

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

我开始自行序列化每个自定义类以追踪问题,但鉴于上述经验,我不确定这是否可靠。不过,我在下面粘贴了我的代码的简化示例。有问题的类是 MyClass2 -> MyClass5 和 MyClass3。但是我在这些课程中看不到任何不寻常的东西。

任何建议将不胜感激。

[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; }
}

标签: c#protobuf-net

解决方案


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

然而!如果您同时开始序列化类型,则可能会出现一些奇怪的时序场景 - 通常在 Web 服务器等上。这里的一个很好的解决方法是确保所有准备工作尽早发生,例如在您可以执行的启动代码中:

Serializer.PrepareSerializer<MyParentClass>();

(也许还有其他几个)


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

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

MoreEnergy财产上。

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


推荐阅读