Monday, October 15, 2012

Queryable extensions

It is possible to extend a LINQ vocabulary with some custom methods that will be used later in query providers to build a custom query to outer source. Also, there is a little trick that allows using such extensions in Linq-to-objects expressions.

Here is a standard stub for an IQueryable method:


public static IQueryable<Tuple<int, TKey>> CountBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
{
    return source.Provider.CreateQuery<Tuple<int, TKey>>(
            Expression.Call(
              null,
              ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
              new[] { source.Expression, Expression.Quote(keySelector) }
                                                       ));
}

To add this methods for LINQ-to-Object you have to add the method for IEnumerable as well with same parameters (just replace Expression<Func<...>> with Func<...>) to the same type where IQueryable method is defined:


public static IEnumerable<Tuple<int,TKey>> CountBy<TSource,TKey>(this IEnumerable<TSource> source, Func<TSource,TKey> keySelector)
{
    return source.GroupBy(keySelector).Select(x => Tuple.Create(x.Count(), x.Key));
}