2013-09-19 3 views
0

Я пытаюсь реализовать IEqualityComparer для моего объекта, который в основном определяет, является ли объект старше другого. Следующий простой пример синтезирует то, что я пытаюсь выполнить:Странное поведение в IEqualityComparer

class Program 
{ 
    static void Main(string[] args) 
    { 
     var authorsList = new List<Author>() 
     { 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=11 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=20 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=14 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Fred", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Trevor", Lastname = "Smith", Age=15 }, 
      new Author{ Firstname = "Brian", Lastname = "Smith", Age=11 }, 
      new Author{ Firstname = "Billy", Lastname = "Smith", Age=11 }, 
     }; 
     var authorsListExcept = new List<Author>() 
     { 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Fred", Lastname = "Smith", Age=12 }, 
     }; 
     var authorsList2 = authorsList 
      .Except(authorsListExcept, new AuthorUpdatedComparer()).ToList(); 
    } 
} 

class Author 
{ 
    public string Firstname { get; set; } 
    public string Lastname { get; set; } 
    public int Age { get; set; } 
} 

class AuthorUpdatedComparer : IEqualityComparer<Author> 
{ 
    public bool Equals(Author x, Author y) 
    { 
     return x.Age >= y.Age; 
    } 

    public int GetHashCode(Author obj) 
    { 
     //Check whether the object is null 
     if (Object.ReferenceEquals(obj, null)) return 0; 

     int FirstnameHash = (obj.Firstname ?? "").GetHashCode(); 
     int LastnameHash = (obj.Lastname ?? "").GetHashCode(); 
     int finalResult = FirstnameHash^LastnameHash; 

     return finalResult; 
    } 
} 

Мой результат authorsList2 будет: * Боб Смит с возрастом 20 * Bom Смитом с возрастом 14 * Тревор Смит с 15 лет * Брайан Смит с 11 лет * Билли Смит с 11 лет

Но вместо этого Боб Смит с 14 лет не включен. При отладке я пришел к выводу, что после сравнения с продавцом после того, как Боб Смит с возрастом 20 начал использовать его, был исключен сравнитель, после чего Боб был моложе 20.

Это странное поведение, на мой взгляд, оно должно исключили только тех, кто моложе или с тем же возрастом, что и те, которые включены в список авторовListExcept. Я пытался читать документацию MSDN и то, что я хочу, это должно быть должно произойти: шрифт: http://msdn.microsoft.com/en-us/library/bb336390(v=vs.100).aspx

Любой человек может мне помочь? Спасибо, Hugo Сальгадо

+3

Ваша реализация Equals не имеет для меня большого смысла. > = зависит от предыдущей сортировки списка. При сравнении 20-14 вы получаете разные результаты, зависящие от того, к какому параметру x или y они идут. С этим нет никаких шансов получить стабильные результаты. В уравнении EqualityComparer сравните для равенства и ничего другого. – Ralf

+0

Есть ли у вас другой sugestion делать то, что я хочу. Я хочу изменить свой код, если есть лучший подход. –

+0

@HugoSalgado: Даже не понятно, чего вы хотите достичь здесь. Просьба представить ожидаемый результат и объяснить его. Прямо сейчас, то, что у вас прямо под исходным кодом, не имеет для меня никакого смысла вообще и, в частности, нет ни одного «Бом Смита». –

ответ

1

Следующий запрос LINQ обеспечивает результат, который вы ожидаете:

var result = 
    authorsList.GroupBy(x => Tuple.Create(x.Firstname, x.Lastname)) 
       .SelectMany(g => g.Where(x => authorsListExcept.All(e => e.Firstname != x.Firstname || e.Lastname != x.Lastname || e.Age < x.Age))); 

Следующий запрос также производит этот результат. Он должен работать лучше:

var result = 
    authorsList.GroupBy(x => Tuple.Create(x.Firstname, x.Lastname)) 
       .GroupJoin(authorsListExcept, x => x.Key, 
          x => Tuple.Create(x.Firstname, x.Lastname), 
          (a, e) => a.Where(x => x.Age > e.Select(z => z.Age) 
                  .DefaultIfEmpty(0) 
                  .Max())) 
       .SelectMany(x => x) 

И третий вариант (то же самое, что и предыдущий, но в синтаксисе запроса):

var result = 
    (from a in authorsList 
    group a by Tuple.Create(a.Firstname, a.Lastname) into g 
    join e in authorsListExcept on g.Key equals Tuple.Create(e.Firstname, e.Lastname) into er 
    from age in er.Select(x => x.Age).DefaultIfEmpty() 
    select g.Where(x => x.Age > age)).SelectMany(x => x); 

Интерфейс IEqualityComparer<T> есть для проверки равенства. Это не имеет никакого отношения к любому заказу. Таким образом, вы не можете использовать его так, как вы пытаетесь.

В целом: реализация этого интерфейса должна всегда использовать тот же набор свойств как в реализации GetHashCode, так и в методе Equals.

+1

@TimSchmelter: Я не следую. Но я думаю, что на самом деле ОП не понимал концепцию этого интерфейса. Похоже, он хочет как-то определить порядок и фильтрацию в одно и то же время. –

+0

Спасибо всем за быстрые ответы ... Так в основном вы о том, что мне нужно использовать все первое и последние имена Что-то вроде этого: общественного BOOL Equals (Автор х, автор у) { если (x.Firstname == y.Firstname && x.Lastname == y.Lastname) return x.Age> = y.Age; return false; } Это все еще не работает ... Я не могу использовать метод Age on GetHash, потому что у меня нет возможности сравнить его. Если вы считаете, что это не лучший подход, не стесняйтесь давать мне работу. Снова спасибо всем Hugo –

+1

Нет, это компаратор для * равенства *. Ваш '> =' не имеет абсолютно никакого смысла здесь. –

0

Если я понял, что вы хотите попробовать.

class Program 
{ 
    static void Main(string[] args) 
    { 
     var authorsList = new List<Author>() 
     { 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=11 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=20 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=14 }, 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Fred", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Trevor", Lastname = "Smith", Age=15 }, 
      new Author{ Firstname = "Brian", Lastname = "Smith", Age=11 }, 
      new Author{ Firstname = "Billy", Lastname = "Smith", Age=11 }, 
     }; 
     var authorsListExcept = new List<Author>() 
     { 
      new Author{ Firstname = "Bob", Lastname = "Smith", Age=12 }, 
      new Author{ Firstname = "Fred", Lastname = "Smith", Age=12 }, 
     }; 

     var authorsList2 = authorsList.Where(x => !authorsListExcept.Any(y => y.Firstname == x.Firstname && y.Lastname == x.Lastname && x.Age <= y.Age)); 
    } 
} 

public class Author 
{ 
    public string Firstname { get; set; } 
    public string Lastname { get; set; } 
    public int Age { get; set; } 
} 
Смежные вопросы