嘿,我正在使用LINQ中的Enumerable.Sum()
扩展方法来计算哈希码,并且当代码变大时我遇到OverflowExceptions
的问题。我尝试将调用放在unchecked
块中,但这似乎没有帮助。
该方法的MSDN文档说,如果值太大,它将抛出,但我检查了反射器,这就是:
public static int Sum(this IEnumerable<int> source) {
if (source == null) {
throw Error.ArgumentNull("source");
}
int num = 0;
foreach (int num2 in source) {
num += num2;
}
return num;
}
基于这种反编译,我希望它可以溢出或不取决于调用代码的上下文。为什么它会溢出,我怎么能让它停止?
答案 0 :(得分:9)
代码确实在C#checked
块中执行。问题是反射器没有正确地反编译checked
块,而是将它们显示为正常的数学运算。您可以通过创建一个选中的块,编译代码然后在反射器中反编译来自行验证。
您还可以通过查看IL而不是反编译的C#代码来验证这一点。而不是添加IL操作码,您将看到添加发生在add.ovf。这是抛出溢出的添加版本
L_001a: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::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
答案 1 :(得分:7)
我为通用枚举编写了这个函数。我很乐意听到有关它的任何评论。
public static int SequenceHashCode<T>(IEnumerable<T> seq)
{
unchecked
{
return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0;
}
}
答案 2 :(得分:1)
checked
仅适用于当前块中的表达式,而不适用于任何(已编译的)调用方法。要使用未经检查的数学,您需要在Sum
块中实现自己的unchecked
版本