Microsoft’s Dynamic Linq library has been floating around the internet in one form or another for years. Its been distributed as a raw .cs file, not a NuGet or any sort of supported package. The most central location I’ve found for this is King Wilder’s System.Dynamic.Linq GitHub repo and NuGet package.

I needed support for a couple of things that weren’t included in the original version, namely Sum/Average/Min/Max functions, and that in a dynamically callable way. So I built that, cribbing off of a Sum function found on StackOverflow. The code takes the name of the function you want to call and the name of the property you want to aggregate. It then uses reflection to grab the extension method of the correct type based on the property type you specify and executes it against the IQueryable, returning the result.

After a bit of jiggering, I realized that Sum and Average have totally different signatures than Min/Max for some reason. Adding in separate branches to the code did the trick and I came up with:

/// <summary>
/// Dynamically runs an aggregate function on the IQueryable.
/// </summary>
/// <param name="source">The IQueryable data source.</param>
/// <param name="function">The name of the function to run. Can be Sum, Average, Min, Max.</param>
/// <param name="member">The name of the property to aggregate over.</param>
/// <returns>The value of the aggregate function run over the specified property.</returns>
public static object Aggregate(this IQueryable source, string function, string member)
{
    if (source == null) throw new ArgumentNullException("source");
    if (member == null) throw new ArgumentNullException("member");

    // Properties
    PropertyInfo property = source.ElementType.GetProperty(member);
    ParameterExpression parameter = Expression.Parameter(source.ElementType, "s");
    Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, property), parameter);
    // We've tried to find an expression of the type Expression<Func<TSource, TAcc>>,
    // which is expressed as ( (TSource s) => s.Price );

    var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function);

    // Method
    MethodInfo aggregateMethod = typeof(Queryable).GetMethods().SingleOrDefault(
        m => m.Name == function
            && m.ReturnType == property.PropertyType // should match the type of the property
            && m.IsGenericMethod);

    // Sum, Average
    if (aggregateMethod != null)
    {
        return source.Provider.Execute(
            Expression.Call(
                null,
                aggregateMethod.MakeGenericMethod(new[] { source.ElementType }),
                new[] { source.Expression, Expression.Quote(selector) }));
    }
    // Min, Max
    else
    {
        aggregateMethod = typeof(Queryable).GetMethods().SingleOrDefault(
            m => m.Name == function
                && m.GetGenericArguments().Length == 2
                && m.IsGenericMethod);

        return source.Provider.Execute(
            Expression.Call(
                null,
                aggregateMethod.MakeGenericMethod(new[] { source.ElementType, property.PropertyType }),
                new[] { source.Expression, Expression.Quote(selector) }));
    }
}

I've submitted a pull request with this function to kahnau's repo, and he seems pretty responsive about accepting pull requests, so this will likely be in that NuGet soon.