使用Lambda表达式代替IComparer参数


76

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


Answers:


64

正如Jeppe指出的那样,如果您使用的是.NET 4.5,则可以使用static方法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);
    }
}

1
可能希望为此类提供一个不同的名称,以避免与库的类冲突。
2013年

语法细节:泛型类的构造函数不能包含<T>类名称的一部分。
Jeppe Stig Nielsen

91

如果您使用的是.NET 4.5,则可以使用static方法Comparer<aClass>.Create

文档:Comparer<T>.Create方法

例:

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

1
可悲的是,我们在.Net 3.5领域大放异彩!无法承受将TFS升级到最新版本所需的庞大费用:-(
2013年

3
@haughtonomous如果那是唯一使您受阻的东西,您是否考虑过转储TFS以便支持其他东西?
Arturo Hernandez 2014年

您是否知道关于为什么我们不能将lambda直接放在那里但需要包装的基本理论(不像“因为它需要lambda以外,还需要其他类型”)?
jw_

@jw_我不确定这背后有多少理论。.OrderBy(Linq)的作者决定不具有接受委托进行比较的重载(如Comparison<TKey>委托)。您可以根据需要创建自己的扩展方法。
杰普·斯蒂格·尼尔森

从理论上讲,接口有2种以上的方法。
jw_

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));

您可以参考我的博客文章,以获得有关此实现的扩展讨论。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.