Extension methods to sum IEnumerable(ulong) and IEnumerable(ulong?)

Yan Cui

I help clients go faster for less using serverless technologies.

This article is brought to you by

Is your CI build step taking too long? Try Depot for free today and experience up to 40x faster build speed!

Unlock faster CI for FREE

Ever tried to use IEnumerable<T>.Sum on an array of unsigned long integers? Well, you can’t, because the Sum method has not been implemented for ulong or ulong?, so to fill in the gap here’s the extension methods you need using more or less the same code as the existing Sum methods:

[CheckParameters]
public static ulong Sum([NotNull] this IEnumerable<ulong> source)
{
    var sum = 0UL;
    foreach (var number in source)
    {
        sum += number;
    }
    return sum;
}

[CheckParameters]
public static ulong? Sum([NotNull] this IEnumerable<ulong?> source)
{
    var sum = 0UL;
    foreach (var nullable in source)
    {
        if (nullable.HasValue)
        {
            sum += nullable.GetValueOrDefault();
        }
    }
    return sum;
}

[CheckParameters]
public static ulong Sum<T>([NotNull] this IEnumerable<T> source, Func<T, ulong> selector)
{
    return source.Select(selector).Sum();
}

[CheckParameters]
public static ulong? Sum<T>([NotNull] this IEnumerable<T> source, Func<T, ulong?> selector)
{
    return source.Select(selector).Sum();
}

I used some custom PostSharp attributes here to do the parameter validation, but you can just as easily substitute them with if null then throw exception code blocks.

UPDATE 10/11/2010:

Using the dynamic type in .Net 4 you can make these extension methods even more useful by making them usable with other value types too.

Traditionally for extension methods like Sum, you’d have to provide an overload for each numeric value type (int, uint, long, etc.) because these numeric value types don’t have a common super type which defines the numeric operators +, -, /, *, etc.

Fortunately, you can now negate this compile time limitation by making it a runtime decision using the new dynamic capabilities:

public static T Sum<T>(this IEnumerable<T> source) where T : struct
{
    return source.Aggregate(default(T), (current, number) => (dynamic) current + number);
}
public static T? Sum<T>(this IEnumerable<T?> source) where T : struct
{
    return source.Where(nullable => nullable.HasValue)
                 .Aggregate(
                     default(T),
                     (current, nullable) => (dynamic) current + nullable.GetValueOrDefault());
}
public static V Sum<T, V>(this IEnumerable<T> source, Func<T, V> selector) where V : struct
{
    return source.Select(selector).Sum();
}
public static V? Sum<T, V>(this IEnumerable<T> source, Func<T, V?> selector) where V : struct
{
    return source.Select(selector).Sum();
}

The obvious fallacy with this approach is that you can now pass custom structures with no defined + operator into these extension methods and no compile errors will be thrown, but a RuntimeBinderException will be thrown by the DLR at runtime with a message like this:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Operator ‘+’ cannot be applied to operands of type ‘xxx’ and ‘xxx’

Whenever you’re ready, here are 4 ways I can help you:

  1. Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
  2. Do you want to know how to test serverless architectures with a fast dev & test loop? Check out my latest course, Testing Serverless Architectures and learn the smart way to test serverless.
  3. I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
  4. Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.

Leave a Comment

Your email address will not be published. Required fields are marked *