4

我有一个带有标志的枚举,我用序列化的 [ProtoMember] 属性装饰并反序列化在我运行 Win7 x64 的本地机器上很好。

但是,我的用例涉及在运行 Windows Server 2008 R2 Enterprise 64 位的服务器上序列化并在我的本地机器上反序列化。当我反序列化时,出现异常:“溢出异常未处理;算术运算导致溢出”。它似乎是从 ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source) 抛出的。

我尝试将枚举更改为 int 并序列化在服务器上/反序列化本地工作。我想使用枚举而不是int。我究竟做错了什么?

不确定这是否是相关信息,但我在服务器上运行的可执行文件是在我的本地机器上构建的。

枚举来自引用的外部 dll。当我在我的解决方案中复制枚举代码时,反序列化工作。仅当我使用来自外部 dll 的枚举(我怀疑源代码未知)并且枚举值大于(似乎)128 时才会引发异常。在我的情况下,Status.Zeta 和 Status。全部抛出异常;其他枚举值正确反序列化。枚举定义如下:

[Flags]
public enum Status
{
    None = 0,
    Alpha = 1,
    Beta = 8,
    Gamma = 16,
    Delta = 32,
    Epsilon = 64,
    Zeta = 132,
    All = 255,
}

我无法更改 dll 中的代码。我怎样才能使这项工作?我需要一个 .proto 文件吗?如果可能的话,我会尽量避免这种情况。

4

2 回答 2

3

这只会影响枚举: byte

哦!发现脑死错误:

case ProtoTypeCode.SByte: Emit(OpCodes.Conv_Ovf_U1); break;
case ProtoTypeCode.Byte: Emit(OpCodes.Conv_Ovf_I1); break;

这将在今天晚些时候被逆转和部署。谢谢。

正确解释:byte是无符号的(0到255),sbyte是有符号的(-128到127);Conv_Ovf_U1基本上是“转换为byte,检查溢出”的 IL(就像checkedC# 中的关键字如何工作),并且Conv_Ovf_I1是“转换为sbyte,检查溢出”。因此,任何超过 127 的值都会触发溢出标志,从而导致异常。这已在 r614 中修复,现已部署。

于 2012-12-31T08:23:12.013 回答
1

这确实有点奇怪。CLR 中可能存在影响 ProtoBuf 的差异(例如,CLR 附带许多不同的 GC)。比较两台机器的 Machine.config 文件可能会发现一些差异。

至于解决问题,您可以尝试使用 ProtoContract 标记枚举本身,并使用 ProtoMember 标记每个枚举成员。后者允许您设置一个 Value 属性供 ProtoBuf 使用。您还可以将 DataFormat 设置为 Fixed 并查看它是否比默认设置更好。

您可以在此处找到一些示例

于 2012-12-27T04:20:51.833 回答