C#中Equals和GetHashCode

Equals和GetHashCode

Equals每一个实现都必须遵循如下约定:ide

  • 自反性(Reflexive): x.equals(x)必须返回true.
  • 对称性(Symmetric): x.equals(y)为true时,y.equals(x)也为true.
  • 传递性(Transitive): 对于任何非null的应用值x,y和z,若是x.equals(y)返回true,而且y.equals(z)也返回true,那么x.equals(z)必须返回true.
  • 一致性(Consistence): 若是屡次将对象与另外一个对象比较,结果始终相同.只要未修改x和y的应用对象,x.equals(y)连续调用x.equals(y)返回相同的值l.
  • 非null(Non-null): 若是x不是null,y为null,则x.equals(y)必须为false

GetHashCode:性能

  • 两个相等对象根据equals方法比较时相等,那么这两个对象中任意一个对象的hashcode方法都必须产生一样的整数。
  • 在咱们未对对象进行修改时,屡次调用hashcode使用返回同一个整数.在同一个应用程序中屡次执行,每次执行返回的整数能够不一致.
  • 若是两个对象根据equals方法比较不相等时,那么调用这两个对象中任意一个对象的hashcode方法,不一同的整数。但不一样的对象,产生不一样整数,有可能提升散列表的性能.

IEqualityComparer实现

下面咱们建立一个学生类,从而进一步的实现咱们对象数据的对比flex

public class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }
    }

经过以下代码咱们将经过distinct方法实现咱们的过滤.code

class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{ Name = "MR.A", Age = 32},
                new Student{ Name = "MR.B", Age = 34},
                new Student{ Name = "MR.A", Age = 32}  
            };
            Console.WriteLine("distinctStudents has Count = {0}", students.Distinct().Count());//distinctStudents has Count = 3
            Console.ReadLine();
        }
    }

咱们须要达到的是忽略相同数据的对象,可是并无达到咱们如期的效果.由于是distinct默认比较的是对象的引用...因此这样达不到咱们预期效果.那咱们修改一下来实现咱们预期效果.对象

在默认状况下Equals具备如下行为:get

  • 若是实例是引用类型,则只有引用相同时, Equals才会返回true。
  • 若是实例是值类型,则仅当类型和值相同时, Equals才会返回true。

Distinct (IEnumerable , IEqualityComparer ) string

经过使用指定的 IEqualityComparer 对值进行比较,返回序列中的非重复元素. hash

类型参数

  • TSource source 的元素类型。it

    参数

  • source IEnumerable 要从中移除重复元素的序列。
  • comparer IEqualityComparer 用于比较值的 IEqualityComparer class

返回

  • IEnumerable
    一个包含源序列中的非重复元素的 IEnumerable

咱们来看以下代码片断

public class StudentComparator : EqualityComparer<Student>
    {
        public override bool Equals(Student x,Student y)
        {
            return x.Name == y.Name && x.Age == y.Age;
        }

        public override int GetHashCode(Student obj)
        {
            return obj.Name.GetHashCode() * obj.Age;
        }
    }

上述代码片断若是两个Equals返回的true而且GetHashCode返回相同的哈希码,则认为两个对象相等.

重写Equals和GetHashCode

var stu1 = new Student { Name = "MR.A", Age = 32 };
var stu2 = new Student { Name = "MR.A", Age = 32 };
   
bool result = stu1.Equals(stu2); //false because it's reference Equals

上述代码片断执行后结果非预期效果.咱们将进一步的去实现代码,以达到预期效果....

public class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public override bool Equals(object obj)
        {
            var stu = obj as Student;
            if (stu == null) return false;
            return Name == stu.Name && Age == stu.Age; 
        }
        public override int GetHashCode()
        {
            return Name.GetHashCode() * Age;
        }
    }
    
  var stu1 = new Student { Name = "MR.A", Age = 32 };
  var stu2 = new Student { Name = "MR.A", Age = 32 };

  bool result = stu1.Equals(stu2); //result is true

咱们再使用LINQ Distinct方法进行过滤和查询,同时将会检查Equals和GetHashCode

List<Student> students = new List<Student>
    {
        new Student{ Name = "MR.A", Age = 32},
        new Student{ Name = "MR.B", Age = 34},
        new Student{ Name = "MR.A", Age = 32}
    };
    Console.WriteLine("distinctStudents has Count = {0}", students.Distinct().Count()); //distinctStudents has Count = 2
相关文章
相关标签/搜索