Extension methods on lamdba expressions don't work, unfortunately

Over the Christmas holidays, I thought I'd experiment with something I'd been thinking about a little - sorting a generic IList<T>. Now, before anyone gets huffy, I'm well aware of OrderBy in LINQ to Objects. However, sometimes you want to sort collections in-place, and as IList<T> provides random access, there's no reason we shouldn't be able to. Now, I do like the way that OrderBy allows multiple criteria to be specified, whether they should be applied in an ascending or descending fashion, and by way of just "compare by this projection" rather than having to actually implement the comparison yourself. I thought I could probably make use of those ideas again.

Unlike in LINQ to Objects, the sort would occur immediately, which means I couldn't use quite the chained syntax of OrderBy(...).ThenBy(...).ThenByDescending(...) but my plan was to allow code like this:

List<Person> myList = ...;

myList.SortBy((person => person.Name).Ascending(),
              (person => person.DateOfBirth).Descending(),
              (person => person.SocialSecurityNumber).Ascending());

Because each of the different output types involved might be different, that would only work for as many overloads as I'd implement. An alternative would be:

Comparer<Person> sorter = Comparer.By(person => person.Name)
                          .ThenByDescending(person => person.DateOfBirth)
                          .ThenBy(person => person.SocialSecurityNumber);

sorter.Sort(myList);

I did like the idea of the Ascending and Descending extension methods though, operating on Func<T1,T2>. Unfortunately, the dot operator doesn't work on lambda expressions, even though the expression itself is implicitly convertible to Func<T1,T2>.

My plan isn't entirely scuppered - the latter syntax will still work, and there are probably some alternatives I can work out. I think there are nice possibilities around extension methods and delegates though, and it's a shame they're not useful for lambda expressions. Ah well.

Published Tuesday, January 08, 2008 11:37 PM by skeet
Filed under: ,

Comments

# re: Extension methods on lamdba expressions don't work, unfortunately

Check out this article which make help you out.  In C# you cannot infer the type of the lambda expression in a vacuum.  Instead you have to use another inference level to get the type.  Using the trick outlined in this article you should be able to write

Lambda.Create((person) => person.Name).Ascending()

Still a bit wordy but it should work.  

blogs.msdn.com/.../c-lambda-type-inference.aspx

Tuesday, January 08, 2008 6:25 PM by Jared Parsons

# re: Extension methods on lamdba expressions don't work, unfortunately

Well, I can get the following to compile:

people.SortBy(

 people.Asc(p=>p.Name),

 people.Desc(p=>p.DateOfBirth),

 people.Asc(p=>p.SSN));

Having IList<T> extension methods (Asc/Desc) just to get the generic type inference is a bit hacky, but it works...

SortBy<T>(this IList<T> list, params IComparer<T>[] comparers)

IComparer<T> Asc<T, TValue>(this IList<T> list, Func<T, TValue> selector)

IComparer<T> Asc<T, TValue>(this IList<T> list, Func<T, TValue> selector, IComparer<TValue> comparer)

IComparer<T> Desc<T, TValue>(this IList<T> list, Func<T, TValue> selector)

IComparer<T> Desc<T, TValue>(this IList<T> list, Func<T, TValue> selector, IComparer<TValue> comparer)

Wednesday, January 09, 2008 2:28 AM by Marc Gravell

# re: Extension methods on lamdba expressions don't work, unfortunately

I'm aware that type inference doesn't happen in a vacuum - but here there wouldn't be a vacuum. There would be a set of possible types to attempt to convert to, as defined by the extension methods which accept that type of delegate.

I certainly think it's technically feasible for the future - I doubt that it'll happen, but I suspect there are a few nice uses it could be put to.

Jon

Wednesday, January 09, 2008 2:54 AM by skeet

Leave a Comment

(required) 
(required) 
(optional)
(required)