Enumerable.Sum()溢出

嘿,我正在使用LINQ的Enumerable.Sum()扩展方法来计算哈希码,并且在代码变大时遇到OverflowExceptions问题。 我尝试将调用置于unchecked块中,但这似乎没有帮助。

该方法的MSDN文档说,如果值太大,它将抛出,但我检查了reflection器,这就是:

 public static int Sum(this IEnumerable source) { if (source == null) { throw Error.ArgumentNull("source"); } int num = 0; foreach (int num2 in source) { num += num2; } return num; } 

根据这个反编译,我希望它可以溢出或不取决于调用代码的上下文。 为什么它会溢出,我怎么能让它停止?

代码确实在C# checked块中执行。 问题是reflection器没有正确反编译已checked块,而是将它们显示为正常的数学运算。 您可以通过创建一个选中的块,编译代码然后在reflection器中反编译来validation这一点。

您还可以通过查看IL而不是反编译的C#代码来validation这一点。 而不是添加IL操作码,您将看到添加发生在add.ovf。 这是抛出溢出的add版本

 L_001a: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1::get_Current() L_001f: stloc.1 L_0020: ldloc.0 L_0021: ldloc.1 L_0022: add.ovf <-- This is an overflow aware addition L_0023: stloc.0 L_0024: ldloc.2 

没有办法让这个特殊的方法不抛出溢出。 您最好的选择如下

  1. 切换到较大的类型,如long
  2. 编写自己的Sum版本,不使用检查添加

我为通用枚举写了这个函数。 我很想听听有关它的任何评论。

 public static int SequenceHashCode(IEnumerable seq) { unchecked { return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0; } } 

checked仅适用于当前块中的表达式,而不适用于任何(已编译的)调用方法。 要使用未经检查的数学,您需要在unchecked块中实现自己的Sum版本