使用 lambda 表达式代替 IComparer 参数

C # 是否可以在方法调用中将 lambda 表达式作为 IComparer 参数传递?

例如

var x = someIEnumerable.OrderBy(aClass e => e.someProperty,
(aClass x, aClass y) =>
x.someProperty > y.SomeProperty ?  1 : x.someProperty < y.SomeProperty ?  -1 : 0);

我不能完全编译这个,所以我猜不会,但它似乎是如此明显的 lambdas 和匿名代表之间的协同作用,我觉得我一定是做了什么愚蠢的错误。

TIA

44837 次浏览

If you're on .NET 4.5, you can use the static method Comparer<aClass>.Create.

Documentation: Comparer<T>.Create Method .

Example:

var x = someIEnumerable.OrderBy(e => e.someProperty,
Comparer<aClass>.Create((x, y) => x.someProperty > y.SomeProperty ?  1 : x.someProperty < y.SomeProperty ?  -1 : 0)
);

As Jeppe points out, if you're on .NET 4.5, you can use the static method Comparer<T>.Create.

If not, this is an implementation that should be equivalent:

public class FunctionalComparer<T> : IComparer<T>
{
private Func<T, T, int> comparer;
public FunctionalComparer(Func<T, T, int> comparer)
{
this.comparer = comparer;
}
public static IComparer<T> Create(Func<T, T, int> comparer)
{
return new FunctionalComparer<T>(comparer);
}
public int Compare(T x, T y)
{
return comparer(x, y);
}
}

If you consistently want to compare projected keys (such as a single property), you can define a class that encapsulates all the key comparison logic for you, including null checks, key extraction on both objects, and key comparison using the specified or default inner comparer:

public class KeyComparer<TSource, TKey> : Comparer<TSource>
{
private readonly Func<TSource, TKey> _keySelector;
private readonly IComparer<TKey> _innerComparer;


public KeyComparer(
Func<TSource, TKey> keySelector,
IComparer<TKey> innerComparer = null)
{
_keySelector = keySelector;
_innerComparer = innerComparer ?? Comparer<TKey>.Default;
}


public override int Compare(TSource x, TSource y)
{
if (object.ReferenceEquals(x, y))
return 0;
if (x == null)
return -1;
if (y == null)
return 1;


TKey xKey = _keySelector(x);
TKey yKey = _keySelector(y);
return _innerComparer.Compare(xKey, yKey);
}
}

For convenience, a factory method:

public static class KeyComparer
{
public static KeyComparer<TSource, TKey> Create<TSource, TKey>(
Func<TSource, TKey> keySelector,
IComparer<TKey> innerComparer = null)
{
return new KeyComparer<TSource, TKey>(keySelector, innerComparer);
}
}

You could then use this like so:

var sortedSet = new SortedSet<MyClass>(KeyComparer.Create((MyClass o) => o.MyProperty));

You can refer to my blog post for an expanded discussion of this implementation.