Подтвердить что ты не робот

Использование выражения лямбда вместо аргумента IComparer

Возможно ли, чтобы С# передал лямбда-выражение в качестве аргумента IComparer в вызове метода?

например, что-то вроде

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

Я не могу заставить это скомпилировать, поэтому я не думаю, что это не так, но кажется очевидным синергизмом между лямбдами и анонимными делегатами, что я чувствую, что должен делать что-то глупое неправильно.

ТИА

4b9b3361

Ответ 1

Как указывает Джеппе, если вы используете .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);
    }
}

Ответ 2

Если вы используете .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)
    );

Ответ 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);
    }
}

Для удобства метод factory:

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

Вы можете обратиться к моему сообщению в блоге для расширенного обсуждения этой реализации.