2009-07-01 3 views
29

Я этоIEqualityComparer для анонимного типа

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

Я хотел бы это сделать, если его там, где разрешен

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

Я попытался с помощью универсального LambdaComparer, но так как им с помощью анонимных типов нет типа связать его с.

«Помоги мне Оби-Ван Кеноби, ты моя единственная надежда»

+3

Отличный вопрос, я просто искал то же самое. Невероятно, что это не в стандартной библиотеке. – orip

+0

Это может помочь [Обернуть делегата в IEqualityComparer] (http://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer) – marbel82

ответ

16

Хитрость заключается в том, чтобы создать компаратор, который работает только на предполагаемых типах. Например:

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

Теперь я могу сделать следующее ... Hacky решение:

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

Очень гладкий. Я думаю, что в интересах написания чистого кода я должен создать интерфейс для использования в качестве Т в IEqualityComparer . – kjgilla

+0

Я не мог решить проблему. Смотри ниже. – Tormod

3

Большую часть времени, когда вы сравниваете (для равенства или сортировки) вы заинтересованы в выборе ключей для сравнения, а не для метода равенства или сравнения (это идея API-интерфейса списка Python).

Приведен пример сравнения равенством here.

0

Отмечу, что ответ JaredPar не совсем отвечает на вопрос, поскольку заданные методы, такие как Distinct и Except, требуют IEqualityComparer<T> не IComparer<T>. Далее предполагается, что IEquatable будет иметь подходящий GetHashCode и, безусловно, имеет подходящий метод Equals.

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

Если такой же вывод из трюка статического класса используется как в ответе JaredPar.

Для получения более общей информации вы можете указать два Func s: a Func<T, T, bool> для проверки равенства и Func<T, T, int> для выбора хеш-кода.

+0

Хотя ответ JaredPar о сравнении, он дает представление о том, как уйти от него. – nawfal