web-dev-qa-db-fra.com

Utilisation de l'expression lambda à la place de l'argument IComparer

Est-il possible avec C # de passer une expression lambda comme argument IComparer dans un appel de méthode?

par exemple quelque chose comme

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

Je n'arrive pas à faire compiler cela, donc je suppose que non, mais il semble qu'une synergie si évidente entre lambdas et les délégués anonymes que je pense que je dois faire quelque chose de stupidement mauvais.

TIA

57
haughtonomous

Comme le souligne Jeppe, si vous êtes sur .NET 4.5, vous pouvez utiliser la méthode statique Comparer<T>.Create.

Sinon, c'est une implémentation qui devrait être équivalente:

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);
    }
}
47
Timothy Shields

Si vous êtes sur .NET 4.5, vous pouvez utiliser la méthode statique Comparer<aClass>.Create.

Documentation: Comparer<T>.Create Méthode .

Exemple:

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

Si vous souhaitez systématiquement comparer les clés projetées (comme une seule propriété), vous pouvez définir une classe qui encapsule pour vous toute la logique de comparaison de clés, y compris les vérifications nulles, l'extraction de clés sur les deux objets et la comparaison de clés à l'aide de l'intérieur spécifié ou par défaut comparateur:

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

Pour plus de commodité, une méthode d'usine:

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

Vous pouvez alors utiliser ceci comme ceci:

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

Vous pouvez vous référer à mon article de blog pour une discussion approfondie de cette implémentation.

3
Douglas