2009-07-01 14 views
29

ho questoIEqualityComparer per tipo anonimo

var n = ItemList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList(); 
n.AddRange(OtherList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList();); 

vorrei fare questo se si dove consentito

n = n.Distinct((x, y) => x.Vchr == y.Vchr)).ToList(); 

Ho provato ad utilizzare il generico LambdaComparer ma dal momento che im utilizzando tipi anonimi non v'è alcun tipo associarlo con.

"Aiutami Obi Wan Kenobi, sei la mia unica speranza"

+3

Ottima domanda, stavo solo cercando la stessa cosa. Incredibile non è nella libreria standard. – orip

+0

Potrebbe essere d'aiuto [Avvolgere un delegato in un IEqualityComparer] (http://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer) – marbel82

risposta

16

Il trucco è quello di creare un operatore di confronto che funziona solo sui tipi di dedurre. Per esempio:

public class Comparer<T> : IComparer<T> { 
    private Func<T,T,int> _func; 
    public Comparer(Func<T,T,int> func) { 
    _func = func; 
    } 
    public int Compare(T x, T y) { 
    return _func(x,y); 
    } 
} 

public static class Comparer { 
    public static Comparer<T> Create<T>(Func<T,T,int> func){ 
    return new Comparer<T>(func); 
    } 
    public static Comparer<T> CreateComparerForElements<T>(this IEnumerable<T> enumerable, Func<T,T,int> func) { 
    return new Comparer<T>(func); 
    } 
} 

ora posso fare quanto segue ... soluzione hacky:

var comp = n.CreateComparerForElements((x, y) => x.Vchr == y.Vchr); 
+0

Molto lucido. Sto pensando però che nell'interesse di scrivere codice pulito dovrei creare un'interfaccia da utilizzare come T in un Comparto IEquality . – kjgilla

+0

Non sono riuscito a risolvere il problema. Vedi sotto. – Tormod

3

maggior parte del tempo quando si confronta (per l'uguaglianza o fascicolazione) siete interessati nella scelta delle chiavi per confrontare, non con l'uguaglianza o il metodo di confronto stesso (questa è l'idea alla base dell'API di ordinamento di Python).

C'è un esempio di confronto di uguaglianza chiave here.

0

Ho notato che la risposta di JaredPar non risponde alla domanda in quanto i metodi impostati come Distinct ed Except richiedono uno IEqualityComparer<T> non uno IComparer<T>. Quanto segue presuppone che un IEquatable abbia un GetHashCode adatto e sicuramente ha un metodo Equals adatto.

public class GeneralComparer<T, TEquatable> : IEqualityComparer<T> 
{ 
    private readonly Func<T, IEquatable<TEquatable>> equatableSelector; 

    public GeneralComparer(Func<T, IEquatable<TEquatable>> equatableSelector) 
    { 
     this.equatableSelector = equatableSelector; 
    } 

    public bool Equals(T x, T y) 
    { 
     return equatableSelector.Invoke(x).Equals(equatableSelector.Invoke(y)); 
    } 

    public int GetHashCode(T x) 
    { 
     return equatableSelector(x).GetHashCode(); 
    } 
} 

public static class GeneralComparer 
{ 
    public static GeneralComparer<T, TEquatable> Create<T, TEquatable>(Func<T, TEquatable> equatableSelector) 
    { 
     return new GeneralComparer<T, TEquatable>(equatableSelector); 
    } 
} 

Dove si utilizza la stessa inferenza di un trucco di classe statico come nella risposta di JaredPar.

Per essere più generale è possibile fornire due Func s: a Func<T, T, bool> per controllare l'uguaglianza e Func<T, T, int> per selezionare un codice hash.

+0

Sebbene la risposta di JaredPar riguardi il confronto, dà l'idea di come procedere. – nawfal