Expressions C # lambda et IComparer

J’utilise des expressions lambda pour sortinger et rechercher un tableau en C #. Je ne souhaite pas implémenter l’interface IComparer dans ma classe, car je dois sortinger et rechercher sur plusieurs champs membres.

class Widget { public int foo; public void Bar() { Widget[] widgets; Array.Sort(widgets, (a, b) => a.foo.CompareTo(b.foo)); Widget x = new Widget(); x.foo = 5; int index = Array.BinarySearch(widgets, x, (a, b) => a.foo.CompareTo(b.foo)); } } 

Bien que le sorting fonctionne correctement, la recherche binary donne une erreur de compilation. Impossible de convertir l’expression lambda en type ‘System.Collections.IComparer ‘ car il ne s’agit pas d’un type de délégué . Pour une raison quelconque, Sort comporte des surcharges pour IComparer et Comparaison, mais BinarySearch ne prend en charge que IComparer. Après quelques recherches, j’ai découvert le ComparisonComparer maladroit ComparisonComparer pour convertir la comparaison en IComparer:

 public class ComparisonComparer : IComparer { private readonly Comparison comparison; public ComparisonComparer(Comparison comparison) { this.comparison = comparison; } int IComparer.Compare(T x, T y) { return comparison(x, y); } } 

Cela permet à la recherche binary de fonctionner comme suit:

 int index = Array.BinarySearch( widgets, x, new ComparisonComparer((a, b) => a.foo.CompareTo(b.foo))); 

Beurk. Y a-t-il un moyen plus propre?

Une option consiste à créer quelque chose comme ProjectionComparer . J’ai une version de cela dans MiscUtil – elle crée fondamentalement un IComparer partir d’une projection.

Donc, votre exemple serait:

 int index = Array.BinarySearch(widgets, x, ProjectionComparer.Create(x => x.foo)); 

Ou vous pouvez implémenter vos propres méthodes d’extension sur T[] pour faire le même genre de chose:

 public static int BinarySearchBy( this TSource[] array, TSource value, Func keySelector) { return Array.BinarySearch(array, value, ProjectionComparer.Create(array, keySelector)); } 

Vous pouvez utiliser ma classe ValueComparer :

 int index = Array.BinarySearch( widgets, x, new ValueComparer(x => x.Foo) ); 

Vous pouvez comparer plusieurs propriétés en passant plusieurs expressions lambda.

Essaye ça:

 public static class ComparisonEx { public static IComparer AsComparer(this Comparison @this) { if (@this == null) throw new System.ArgumentNullException("Comparison @this"); return new ComparisonComparer(@this); } public static IComparer AsComparer(this Func @this) { if (@this == null) throw new System.ArgumentNullException("Func @this"); return new ComparisonComparer((x, y) => @this(x, y)); } private class ComparisonComparer : IComparer { public ComparisonComparer(Comparison comparison) { if (comparison == null) throw new System.ArgumentNullException("comparison"); this.Comparison = comparison; } public int Compare(T x, T y) { return this.Comparison(x, y); } public Comparison Comparison { get; private set; } } } 

Il vous permet d’utiliser ce code:

 Comparison c = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); IComparer icc = c.AsComparer(); Func f = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); IComparer icf = f.AsComparer();