我们可以使用LINQ扩展方法SequenceEqual使用IEqualityComparer接口逐字段比较两个复杂集合吗

时间:2019-05-23 06:06:37

标签: c# linq iequalitycomparer

我正在尝试使用IEqualityComparer逐字段比较2个集合中的2个字段。 IEqualityComparer仅比较1个字段“名称”。我也想比较“标记”。

在Java中,我们具有comparator接口,用于比较Equals方法中的多个字段。

using System;
using System.Linq;
using System.Collections.Generic;

    public class Program
    {
        public static void Main()
        {
            IList<Student> studentList1 = new List<Student>()
            {
                new Student(){ name="aaaaa", mark = 95, },
                new Student(){ name="bbbb", mark = 25, },
                new Student(){ name="ccc",  mark = 80 }
            };

            IList<Student> studentList2 = new List<Student>()
            {
                new Student(){ name="aaaaa", mark = 95, },
                new Student(){ name="bbbb", mark = 5, },
                new Student(){ name="ccc",  mark = 80 }
            };

            bool isEqual = studentList1.SequenceEqual(studentList2, new StudentComparer());
            Console.WriteLine("Names in 2 collections are {0}", isEqual?"equal":"not equal");   
        }
    }

    public class Student
    {
        public string name { get; set; }
        public int mark { get; set; }
    }

    public class StudentComparer : IEqualityComparer<Student>
    {
        public bool Equals(Student x, Student y)
        {
            if (x.name == y.name)
                return true;
            return false;
        }

        public int GetHashCode(Student obj)
        {
            return obj.GetHashCode();
        }
    }

实际结果: 2个集合中的名称相等 预期结果: 2个集合中的名称相等 2个收藏中的分数不相等

4 个答案:

答案 0 :(得分:3)

您的问题是Object.GetHashCode()在对象之间必然是唯一的。这意味着当SequenceEqual(…)调用comparer.GetHashCode(…)时,它将为对象的不同实例获得不同的值,尽管您在StudentComparer.Equals(…)中声明了它们相等。

所有这些意味着,您应该返回仅在根据IEqualityComparer唯一的Student实例唯一的情况下唯一的哈希码。例如,您可以将StudentComparer.GetHashCode(Student obj)的实现更改为: return obj.name.GetHashCode()

答案 1 :(得分:1)

需要像这样正确实现相等比较器(此代码由R#生成):

public sealed class StudentComparer  : IEqualityComparer<Student>
{
    public bool Equals(Student x, Student y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(x, null)) return false;
        if (ReferenceEquals(y, null)) return false;
        if (x.GetType() != y.GetType()) return false;
        return string.Equals(x.name, y.name) && x.mark == y.mark;
    }

    public int GetHashCode(Student obj)
    {
        unchecked
        {
            return ((obj.name != null ? obj.name.GetHashCode() : 0) * 397) ^ obj.mark;
        }
    }
}

PS Why is '397' used for ReSharper GetHashCode override?

答案 2 :(得分:0)

基本上,您需要检查Equals方法中的名称和标记是否相等,并分别获取name属性的哈希码和{{ 1}}正常工作。

将代码修改为此:

mark

输出:

IEqualityComparer

答案 3 :(得分:-2)

我建议您将IEquatable接口添加到您的Student类中,因为它的代码更少,更清楚了您想要达到的目标:

public class Student : IEquatable<Student>
{
    public string name { get; set; }
    public int mark { get; set; }

public bool Equals(Student other)
    {
        if (string.Equals(name, other.name) && mark == other.mark)
        {
            return true;
        }

        return false;
    }
}

您可以忽略其他的StudentComparer实现。