Enumerable.Sum never returns null

I wrote the following code recently, and was surprised when ReSharper warned me that the condition is always true:

IEnumerable<int?> values = // get some values
int? sum = values.Sum();
if (sum.HasValue) { /* this code is always executed */ }

It’s even more surprising when you consider the following difference:

int?[] values = new int?[] { 1, null };
int? sum1 = values.Sum(); // returns 1
int? sum2 = values[0] + values[1]; // returns null

Here, sum1 is 1, but sum2 is null.

Since Sum<int?> never returns null (not even for any empty sequence, or a sequence containing all nulls), it’s odd that its return type is int?, implying that null is a possible return value. Anders explains that this return type is to keep the pattern of T Sum<T>(IEnumerable<T>) for nullable types.

But what if you want Sum to return null if the sequence contains a null? This is easy to simulate using Aggregate, as C# already propagates nulls properly when using the addition operator:

public static class EnumerableUtility
{
    public static int? NullableSum(this IEnumerable<int?> values)
    {
        return values.Aggregate((int?) 0, (sum, value) => sum + value);
    }
}

The initial value of 0 is specified to force the sum of an empty list to be zero; you could change it to `default(int?)` to make an empty list sum to `null`. A possible optimisation would be to rewrite it with a foreach loop that returns null as soon as the first null in the sequence is found.

Update: My very smart coworker points out that changing the initial aggregate value to default(int?) makes the function return null for any input. (This is probably a good reason to include a full unit test suite with every blog post…) A custom enumerator (or test of values.Any() first) could be used if returning null as the sum of an empty sequence is desired.

Posted by Bradley Grainger on June 01, 2009