2013-05-30 3 views
45

Est-il possible avec C# de transmettre une expression lambda en tant qu'argument IComparer dans un appel de méthode?Utilisation de l'expression lambda à la place de l'argument IComparer

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 ne peux pas tout à fait obtenir ce pour compiler si je devine pas, mais il semble qu'une telle synergie évidente entre lambdas et délégués anonymes que je sens que je dois faire quelque chose bêtement faux.

TIA

+1

Réponse possible ici: http://stackoverflow.com/questions/9824435/interface-implementing-anonymous-class-in-c –

Répondre

37

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

Dans le cas contraire, cela est une mise en œuvre qui devrait être équivalent:

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

Peut vouloir donner cette classe un nom différent pour éviter les conflits avec la classe de la bibliothèque – Servy

+0

@Servy Good point - changed –

+0

Syntactic detail: Le constructeur d'une classe générique ne doit pas inclure la partie '' du nom de la classe –

50

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

Documentation: Comparer<T>.Create Method.

Exemple:

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

Malheureusement, nous languissons dans .Net 3.5 terre! Ne peut pas se permettre le méga-coin nécessaire pour mettre à niveau TFS à la dernière version :-( – haughtonomous

+2

@haughtonomous si c'est la seule chose qui vous retient, avez-vous envisagé de dumping TFS en faveur de quelque chose d'autre? –

3

Si vous voulez toujours pour comparer les clés projetées (comme une seule propriété), vous pouvez définir une classe qui encapsule toute la comparaison clé logique pour vous, y compris les contrôles null, extraction de la clé sur les deux objets, et les comparaisons clés en utilisant la ou spécifiée par défaut comparateur intérieure:

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 de fabrication:

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 ensuite utiliser cela comme si:

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

Vous pouvez vous référer à mon blog post pour une discussion élargie de cette mise en œuvre.

Questions connexes