Passing type members generically to operate on generic collection

281 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 best solutions below

0
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
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();
    }
}