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:
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:
.ThenByDescending(person => person.DateOfBirth)
.ThenBy(person => person.SocialSecurityNumber);
I did like the idea of the
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
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.
3 thoughts on “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.
Well, I can get the following to compile:
Having IList extension methods (Asc/Desc) just to get the generic type inference is a bit hacky, but it works…
SortBy(this IList list, params IComparer comparers)
IComparer Asc(this IList list, Func selector)
IComparer Asc(this IList list, Func selector, IComparer comparer)
IComparer Desc(this IList list, Func selector)
IComparer Desc(this IList list, Func selector, IComparer comparer)
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.