Passing type members generically to operate on generic collection

241 views Asked by At

I'm creating a function that will take some IEnumerable, conduct grouping, ordering, take some top N elements, and return a list of those elements. It may likely do more later on, that's why I want to make it into a function and not just use LINQ directly.

I rely on anonymous delegate to specify which members of type T will be used to group and sort the collection.

    public IEnumerable<T> GetList(IEnumerable<T> collection, Func<T, object> groupBy, Func<T, object> orderBy, int howMany)
    {
        var group = collection
            .GroupBy(groupBy)
            .Select(x => x.OrderBy(orderBy).Take(howMany))
            .Aggregate((l1, l2) => l1.Concat(l2));

        return group.ToList();
    }

And use like this:

        new CollectionGroupPicker<NumericDomainObject>().GetList(list, x => x.GroupableField, x => x.OrderableField, 2).ToList();

My question is - is there a better way to pass which member of type T I will use to group and sort by? I'm using object here, but is there a better way?

2

There are 2 answers

0
Samuel Neff On BEST ANSWER

Instead of specifying object you should specify the group and select keys as generic parameters. Their type will be automatically inferred from usage and the caller can specify a lambda with any return type.

public IEnumerable<T> GetList<TGroupKey, TOrderKey>(IEnumerable<T> collection, 
                                                    Func<T, TGroupKey> groupBy, 
                                                    Func<T, TOrderKey> orderBy, 
                                                    int howMany)
{
    var group = collection
        .GroupBy(groupBy)
        .Select(x => x.OrderBy(orderBy).Take(howMany))
        .Aggregate((l1, l2) => l1.Concat(l2));
    return group.ToList();
}
0
Alex On

I agree with Samuel use the generic parmater types. Also, why not use SelectMany to flatten the result, and perhaps make it an extension method?

static class GetListExtensionMethods
{
    public static IEnumerable<T> GetList<T, TGroupingField, TOrderingField>(this IEnumerable<T> collection, Func<T, TGroupingField> groupBy, Func<T, TOrderingField> orderBy, int howMany)
    {
        var group = collection
            .GroupBy(groupBy)
            .SelectMany(x => x.OrderBy(orderBy).Take(howMany));
        return group.ToList();
    }
}