Using lambda expression with .OrderBy

It's always bugged me that I could use a lambda expression with List<T>.Sort(), but not with IEnumerable<T>.OrderBy, i.e. given data object Data:

public class Data {
  public int Id;
  public string Name;
  public int Rank;
}

you can sort List<Data> in place like this:

data.Sort((left, right) => {
var cmp = left.Name.CompareTo(right.Name);
  if(cmp != 0) {
    return cmp;
  }
  return right.Rank.CompareTo(left.Rank);
});

But if I had an IEnumerable<Data>, orderby needs a custom IComparer and can't take a lambda.

Fortunately, it is fairly easy to create a generic IComparer that does take a lambda and an extension method to simplify the signature to just a lambda expression:

public static class OrderByExtension {
    private class CustomComparer<T> : IComparer<T> {
        private readonly Func<T,T,int> _comparison;

        public CustomComparer(Func<T,T,int> comparison) {
            _comparison = comparison;
        }

        public int Compare(T x, T y) {
            return _comparison(x, y);
        }
    }

    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> enumerable, Func<T,T,int> comparison) {
        return enumerable.OrderBy(x => x, new CustomComparer<T>(comparison));
    }

    public static IEnumerable<T> OrderByDescending<T>(this IEnumerable<T> enumerable, Func<T,T,int> comparison) {
        return enumerable.OrderByDescending(x => x, new CustomComparer<T>(comparison));
    }
}

Now I can use a lambda just like in sort:

var ordered = unordered.OrderBy((left, right) => {
    var cmp = left.Name.CompareTo(right.Name);
    if(cmp != 0) {
        return cmp;
    }
    return right.Rank.CompareTo(left.Rank);
});

Of course, .OrderByDescending is kind of redundant, since you can invert the order in the lambda just as easily, but is added simply for completeness.