LINQ对象相等性及其正确覆盖方法

3

为什么var excludes = users.Except(matches);没有排除matches

如果我想让相等比较器只使用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());
    }            
}

请注意,在“matches”中,我正在执行“select lu”。 - VoodooChild
2个回答

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

2
只是一种习惯 - 如果我非常确定该类不会被继承或没有继承的理由,我就将其标记为密封类。 - max

3
你的用户类没有重写Equals和GetHashCode,因此使用了默认实现的Equals。在这种情况下,这意味着它比较引用。你创建了两个具有相同值的用户对象,但由于它们是不同的对象,它们比较不相等。
覆盖Equals的替代方法是使用接受IEqualityComparer参数的Except重载方法

“覆盖Equals的另一种选择是使用接受IEqualityComparer的Except重载。”- 这是Max的答案展示的内容吗,还是有所不同? - VoodooChild
2
是的,这正是这种情况。覆盖Equals应谨慎考虑,因为此逻辑将应用于任何使用User对象的地方(但您可能确实需要此行为);提供IEqualityComparer可以将比较规则限制为仅一个调用。顺便说一句,我想知道为什么他们没有创建一个接受更轻量级的Comparison委托的Except重载,这样就不需要声明一个全新的类,因为委托可以是匿名的。 - max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接