views:

91

answers:

2

Hey, I'm using the Enumerable.Sum() extension method from LINQ to compute hash codes, and am having a problem with OverflowExceptions when the code gets big. I tried putting the call in an unchecked block, but that didn't seem to help.

The MSDN documentation for the method says it will throw if the value gets too big, but I checked in reflector and this is all there is:

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

Based on this decompilation, I would expect it to either overflow or not depending on the context of the calling code. Why is it overflowing, and how can I get it to stop?

+4  A: 

The code is indeed executing in a C# checked block. The problem is that reflector doesn't properly decompile checked blocks and instead shows them as normal mathmatical operations. You can verify this yourself by creating a checked block, compiling the code and then decompiling it in reflector.

You can also verify this by looking at the IL instead of the decompiled C# code. Instead of the add IL opcode you'll see that the addition occurs with add.ovf. This is the version of add that throws on overflows

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 

There is no way to get this particular method to not throw on overflow. Your best options are the following

  1. Switch to a larger type such as long
  2. Write your own version of Sum which does not use checked addition
JaredPar
Thanks. I've got to get more comfortable with IL...
Henry Jackson
A: 

checked only applies to expressions in the current block, not any (already-compiled) called method. To use unchecked maths, you'll need to implement your own version of Sum inside an unchecked block

thecoop
So the checked/unchecked distinction is determined at compile time? I would've expected it to be a runtime, depending on the context, but I guess I would be wrong.
Henry Jackson
As JaredPar has answered, it generates different IL commands whether its in a checked or unchecked block; you can't change already-compiled IL
thecoop