2010-10-09 1 views
3

Почему var excludes = users.Except(matches); не исключает matches?равенство объекта linq и правильное его переопределение

Каков правильный способ, если я хочу, чтобы сопоставитель равен использовать только ID? Примеры были бы оценены.

public class User 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public override string ToString() 
    { 
     return ID.ToString() + ":" + Name; 
    } 
} 

private static void LinqTest2() 
{ 
    IEnumerable<User> users = new List<User> 
    { 
     new User {ID = 1, Name = "Jack"}, 
     new User {ID = 2, Name = "Tom"}, 
     new User {ID = 3, Name = "Jim"}, 
     new User {ID = 4, Name = "Joe"}, 
     new User {ID = 5, Name = "James"}, 
     new User {ID = 6, Name = "Matt"}, 
     new User {ID = 7, Name = "Jon"}, 
     new User {ID = 8, Name = "Jill"} 
    }.OfType<User>(); 

    IEnumerable<User> localList = new List<User> 
    { 
     new User {ID = 4, Name = "Joe"}, 
     new User {ID = 5, Name = "James"} 
    }.OfType<User>(); 


    //After creating the two list 
    var matches = from u in users 
        join lu in localList 
        on u.ID equals lu.ID 
        select lu; 
    Console.WriteLine("--------------MATCHES----------------"); 
    foreach (var item in matches) 
    { 
     Console.WriteLine(item.ToString()); 
    } 

    Console.WriteLine("--------------EXCLUDES----------------"); 
    var excludes = users.Except(matches); 
    foreach (var item in excludes) 
    { 
     Console.WriteLine(item.ToString()); 
    }    
} 
+0

Пожалуйста, обратите внимание, что в 'matches' я делаю' выбрать lu' – VoodooChild

ответ

7
sealed class CompareUsersById : IEqualityComparer<User> 
    { 
     public bool Equals(User x, User y) 
     { 
      if(x == null) 
       return y == null; 
      else if(y == null) 
       return false; 
      else 
       return x.ID == y.ID; 
     } 

     public int GetHashCode(User obj) 
     { 
      return obj.ID; 
     } 
    } 

, а затем

var excludes = users.Except(matches, new CompareUsersById()); 
+0

+1: Это работает. Почему вы сделали этот класс «запечатанным»? – VoodooChild

+1

Просто привычка - если я почти уверен, что класс не будет унаследован или нет причин наследовать его, я делаю его запечатанным. – max

3

Ваш класс пользователя не отменяет Equals и GetHashCode поэтому используется реализация по умолчанию Equals. В этом случае это означает, что он сравнивает ссылки. Вы создали два пользовательских объекта с одинаковыми значениями, но поскольку они отличаются друг от друга, они сравниваются с неравными.

Альтернативой переопределению равных является использование overload of Except that takes an IEqualityComparer.

+0

«Альтернатива переопределения Equals является использование перегрузки исключением того, что принимает IEqualityComparer» - Это то, что показал Макс, или что-то другое? – VoodooChild

+2

Да, это именно такой случай. Переопределение «Равно» следует рассматривать с осторожностью, потому что эта логика будет применяться везде, где используется объект «Пользователь» (но вам может понадобиться такое поведение); поставляя 'IEqualityComparer' лимитирует правила сравнения только для одного вызова. Кстати, интересно, почему они сделали перегрузку «Except», которая принимает более легкий делегат «Comparison», который устраняет необходимость объявления целого нового класса, поскольку делегат может быть анонимным. – max

Смежные вопросы