简体   繁体   English

IEqualityComparer上的奇怪行为

[英]Strange behaviour on IEqualityComparer

I'm trying to implement an IEqualityComparer for my object that basically detects if an object is older that another one. 我正在尝试为我的对象实现IEqualityComparer,该对象基本上可以检测某个对象是否比另一个对象旧。 The following simpler example will synthesises what i'm trying to accomplish: 下面的简单示例将综合我要完成的工作:

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

My authorsList2 result would be: * Bob Smith with age 20 * Bom Smith with age 14 * Trevor Smith with age 15 * Brian Smith with age 11 * Billy Smith with age 11 我的authorsList2结果将是:* Bob Smith,年龄20岁* Bom Smith,年龄14岁* Trevor Smith,年龄15岁* Brian Smith,年龄11岁* Billy Smith,年龄11岁

But instead of this the Bob Smith with age 14 is not included. 但与此相反,不包括14岁的鲍勃·史密斯。 When debugging I reached the conclusion that the Comparer after included Bob Smith with Age 20 start to using it has a comparer excluding then after all the Bob's younger than 20. 调试时,我得出的结论是,将Bob年龄在20岁以下的鲍勃·史密斯加入比较器之后,便开始使用它的比较器,而鲍勃·史密斯还不到20岁。

This is a strange behavior in my point of view it should only excluded the ones that are younger or with the same age to those included on the authorsListExcept. 在我看来,这是一种奇怪的行为,它应该只排除那些与authorsListExcept中包含的年龄相同或相同年龄的人。 I tried to read msdn documentation and what I want it should be supposed to happen: font: http://msdn.microsoft.com/en-us/library/bb336390(v=vs.100).aspx 我试图阅读msdn文档,并希望它应该发生:字体: http : //msdn.microsoft.com/zh-cn/library/bb336390(v=vs.100).aspx

Anyone can help me? 有人可以帮助我吗? Thanks, Hugo Salgado 谢谢,雨果·萨尔加多

The following LINQ query provides the result you expect: 以下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)));

The following query also produces this result. 以下查询也会产生此结果。 It should perform better: 它应该表现更好:

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)

And a third option (the same as the previous but in query syntax): 第三个选项(与前一个选项相同,但查询语法相同):

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

The interface IEqualityComparer<T> is there to check for equality . IEqualityComparer<T>接口可用来检查是否相等 It has nothing to do with any ordering. 它与任何排序无关。 As such, you can't use it in the way you try. 因此,您不能以尝试的方式使用它。

In general: An implementation of this interface should always use the exact same set of properties in both the GetHashCode implementation and the Equals method. 通常,此接口的实现应始终在GetHashCode实现和Equals方法中使用完全相同的属性集。

If i have understood what you want try this. 如果我了解您想要的内容,请尝试此。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM