2013-05-30 19 views
45

Czy to możliwe, że C# przekazuje wyrażenie lambda jako argument IComparer w wywołaniu metody?Używanie wyrażenia lambda zamiast argumentu IComparer

np coś

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

nie mogę całkiem się to skompilować więc nie jestem zgadywania, ale wydaje się tak oczywiste synergię między lambda i anonimowe delegatów, że czuję, że musi coś robić głupio źle.

TIA

+1

Możliwa odpowiedź tutaj: http://stackoverflow.com/questions/9824435/interface-implementing-anonymous-class-in-c –

Odpowiedz

37

Jak Jeppe zwraca uwagę, jeśli jesteś na .NET 4.5, można użyć metody statycznej Comparer<T>.Create.

Jeśli nie, jest to realizacja, która powinna być równa:

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

Może chcesz dać tę klasę inna nazwa, aby uniknąć konfliktów z klasą biblioteki – Servy

+0

@Servy Dobry punkt - zmieniony –

+0

Szczegóły syntaktyczne: Konstruktor klasy ogólnej nie może zawierać części nazwy klasy "" –

50

Jeśli jesteś na .NET 4.5, można użyć metody statycznej Comparer<aClass>.Create.

Dokumentacja: Comparer<T>.Create Method.

Przykład:

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

Niestety marniejemy w .Net 3.5 land! Nie stać na mega-klina potrzebnego do uaktualnienia TFS do najnowszej wersji :-( – haughtonomous

+2

@Haughtonomous, jeśli jest to jedyna rzecz, która Cię powstrzymuje, czy rozważałeś odrzucenie TFS na rzecz czegoś innego? –

3

Jeśli konsekwentnie chcesz porównać przewidywane klawiszy (takie jak pojedynczy obiekt), można zdefiniować klasę, która zamyka cały klucz porównania logika dla Ciebie, w tym kontrole null, klucz wydobycia z obu obiektów i klucz porównaniu z zastosowaniem określonego czy ustawiona wewnętrzną porównywarka:

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

dla wygody, metodę fabryczną:

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

Można wtedy użyć tego tak:

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

Można odwołać się do moich blog post do rozszerzonej dyskusji tej realizacji.

Powiązane problemy