使用 lambda 表达式代替 IComparer 参数
Posted
技术标签:
【中文标题】使用 lambda 表达式代替 IComparer 参数【英文标题】:Using lambda expression in place of IComparer argument 【发布时间】:2013-05-26 05:22:31 【问题描述】: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);
我不能完全编译它,所以我猜不是,但 lambda 和匿名委托之间的协同作用似乎如此明显,我觉得我一定是在做一些愚蠢的错误。
TIA
【问题讨论】:
这里可能的答案:***.com/questions/9824435/… 【参考方案1】:如果您使用的是 .NET 4.5,则可以使用静态方法 Comparer<aClass>.Create
。
文档:Comparer<T>.Create
Method 。
例子:
var x = someIEnumerable.OrderBy(e => e.someProperty,
Comparer<aClass>.Create((x, y) => x.someProperty > y.SomeProperty ? 1 : x.someProperty < y.SomeProperty ? -1 : 0)
);
【讨论】:
遗憾的是,我们在 .Net 3.5 土地上苦苦挣扎!买不起将 TFS 升级到最新版本所需的超大楔子:-( @haughtonomous 如果这是唯一阻碍你的事情,你是否考虑过放弃 TFS 以支持其他东西? 你知道为什么我们不能将 lambda 直接放在那里,而是需要一个包装器的基本理论(不像“因为它需要 lambda 以外的类型”)吗? @jw_ 我不确定这背后有多少理论。.OrderBy
(Linq) 的作者决定不使用接受委托进行比较的重载(如 Comparison<TKey>
委托)。如果需要,您可以创建自己的扩展方法。
理论上似乎是接口有2+方法。【参考方案2】:
正如 Jeppe 指出的,如果您使用的是 .NET 4.5,则可以使用静态方法 Comparer<T>.Create
。
如果不是,这应该是等效的实现:
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);
【讨论】:
可能想给这个类一个不同的名字以避免与库的类冲突。 语法细节:泛型类的构造函数不能包含类名的<T>
部分。【参考方案3】:
如果您始终想要比较投影键(例如单个属性),您可以定义一个类,为您封装所有键比较逻辑,包括空检查、两个对象上的键提取以及使用指定的键比较或默认的内部比较器:
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);
为方便起见,工厂方法:
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);
然后你可以像这样使用它:
var sortedSet = new SortedSet<MyClass>(KeyComparer.Create((MyClass o) => o.MyProperty));
您可以参考我的blog post,了解有关此实现的详细讨论。
【讨论】:
以上是关于使用 lambda 表达式代替 IComparer 参数的主要内容,如果未能解决你的问题,请参考以下文章
编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法Lambda表达式代替方法