Passing a lambda expression as parameter to a method?

8.6k views Asked by At

It seems like it'd be a common requirement, but I cannot find a solution to this anywhere.

I have a method which will OrderBy a collection depending on a parameter passed to it.

I'd like to pass the contents of an 'OrderBy' to the method, but cannot work out how to do it.

What I've Tried

I've tried a switch with a string (i.e. if you pass 'Name' it'll hit the case which orders it by name), but this feels 'hacky' and unnecessary.

I know it's something like Func<TEntity, TResult>, but I can't quite crack it.

PSEUDO CODE:

GetOrderedCollection([NOT SURE] orderBy)
{
  return collection.OrderBy(orderBy);
}
5

There are 5 answers

0
Glorfindel On

Does this satisfy your requirements?

    static void Main(string[] args) {           
        var objects = new List<Test>();
        GetOrderedCollection(objects, x => x.Name);
    }

    class Test {
        public string Name { get; set; }
    }

    static IEnumerable<TEntity> GetOrderedCollection<TEntity>(IEnumerable<TEntity> objects, Func<TEntity, object> orderBy) {
        return objects.OrderBy(orderBy);
    }
0
Melvin On

The parameter has to be either a Func or an Action. See the answer to this question for more information.

0
David Arno On

In it's most generic form, your method would need to look like:

IOrderedEnumerable<T1> GetOrderedCollection<T1, T2>(IEnumerable<T1> collection, Func<T1, T2> orderBy)
{
    return collection.OrderBy(orderBy);
}

T1 being the type of the items in the list and T2 being the type of the property of T1 that you want to order on.

0
BgrWorker On

OrderBy is an extension method with the following signature:

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

(source: https://msdn.microsoft.com/it-it/library/bb534966%28v=vs.110%29.aspx )

so your method needs a Func as its argument, where TSource is the List type, and TKey is the type returned by your lambda. An example would be:

public void Method<TSource, TKey>(List<TSource> list, Func<TSource, TKey> func)
        {
            ...
            IOrderedEnumerable<TSource> orderedEnumerable = list.OrderBy(func);
        }

EDIT: I also noticed that in your example code you declared your method as void, bu then you're trying to return an IOrderedEnumerable. If you want to get the ordered collection back, your method needs to have at least an IEnumerable type (but that would defeat the purpose of ordering it, as IEnumerables do not guarantee order. A more likely implementation would be to return a List<TSource> and call list.OrderBy(func).ToList()

0
ryanyuyu On

Yes you are looking for a Func<TEntity, TResult> orderingFunc. The important thing is that the output (the TResult) is an IComparable so that the OrderBy function can properly sort your results.

So something like this will work fine:

public void OrderByDynamic(Func<Model, object> orderByFunc)
{
    collection = collection.OrderBy(orderByFunc); //don't forget to assign the return value
}

You could call this with lambda functions like normal:

OrderByDynamic(m => m.SortObj); //as long as this property/return value is IComparable

A .NET Fiddle demonstrating this idea