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
没有办法让这个特殊的方法不抛出溢出。 您最好的选择如下
- 切换到较大的类型,如
long
- 编写自己的Sum版本,不使用检查添加
我为通用枚举写了这个函数。 我很想听听有关它的任何评论。
public static int SequenceHashCode(IEnumerable seq) { unchecked { return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0; } }
checked
仅适用于当前块中的表达式,而不适用于任何(已编译的)调用方法。 要使用未经检查的数学,您需要在unchecked
块中实现自己的Sum
版本