使用lambda表达式替代IComparer参数

101

使用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 表达式之间有如此明显的协同作用,以至于我感到自己肯定做错了什么傻事。

谢谢先。


1
可能的答案在这里:https://dev59.com/1Wkw5IYBdhLWcg3wirCs - Chris Mantle
3个回答

123

如果您在使用 .NET 4.5 版本,则可以使用静态方法 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 到最新版本所需的巨额费用 :-( - haughtonomous
3
如果那是唯一阻碍你的事情,你是否考虑放弃TFS,转而使用其他工具? - Arturo Hernandez
@jw_ 我不确定这背后有多少理论。.OrderBy(Linq)的作者决定不要重载接受比较委托的方法(例如Comparison<TKey>委托)。如果需要,您可以创建自己的扩展方法。 - Jeppe Stig Nielsen
这个理论似乎是接口有2个或更多的方法。 - jw_
这个问题提供了一个解决方案 https://dev59.com/PHA75IYBdhLWcg3wo6pe。但是为什么SDK没有像 Comparer<T>.Create 这样的包装器呢? - jw_
显示剩余3条评论

72

正如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);
    }
}

1
可能需要给这个类取一个不同的名称,以避免与库中的类发生冲突。 - Servy
语法细节:泛型类的构造函数不应包括类名中的“<T>”部分。 - Jeppe Stig Nielsen

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

您可以查看我的博客文章,以获得有关此实现的更全面讨论。 点击查看

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接