前言
IEqualityComparer<T>
和 IEquatable<T>
是 C#
中用于比较对象的接口,它们有以下区别:
- IEqualityComparer
IEqualityComparer<T>
也是一个泛型接口,定义了两个方法:Equals(T x, T y)
和GetHashCode(T obj)
。
当你需要自定义对象之间的相等性比较逻辑和哈希码计算逻辑时,可以实现IEqualityComparer<T>
接口。 - IEquatable
IEquatable<T>
是一个泛型接口,定义了一个用于比较对象相等性的方法Equals(T other)
。
当你想要在类中自定义相等性比较的逻辑时,可以实现IEquatable<T>
接口。
实现了IEquatable<T>
接口的类可以通过调用Equals
方法来进行对象之间的相等性比较。
IEqualityComparer<T>
IEqualityComparer<T> 是 C#
中用于比较对象相等性的非泛型接口。它定义了两个方法:Equals(object x, object y)
和 GetHashCode(object obj)
。
Equals(object x, object y)
方法用于比较两个对象 x
和 y
是否相等。它返回一个布尔值,指示两个对象是否相等。
GetHashCode(object obj)
方法用于计算对象 obj
的哈希码。哈希码是一个整数,用于在哈希表等数据结构中进行快速查找和比较。
通常情况下,IEqualityComparer
接口用于在没有泛型的情况下,提供自定义的对象相等性比较和哈希码计算逻辑。 你可以实现 IEqualityComparer
接口来定义你自己的比较器,以便在需要自定义对象相等性比较的情况下使用。
using System;
using System.Collections.Generic;
static class Example
{
static void Main()
{
List<Person> personList = newList<Person>()
{
new Person() { Age = 1, Name = "A" },
new Person() { Age = 2, Name = "B" },
new Person() { Age = 3, Name = "C" },
};
IEnumerable<Person> nameDisList =personList.Distinct(newPersonNameEqualityComparer());
IEnumerable<Person> ageDisList =personList.Distinct(newPersonAgeEqualityComparer());
Console.WriteLine(string.Join(",",nameDisList));
Console.WriteLine(string.Join(",",ageDisList));
}
}
class PersonNameEqualityComparer :IEqualityComparer<Person>
{
public bool Equals(Person b1, Person b2)
{
if (ReferenceEquals(b1, b2))
return true;
if (b2 is null || b1 is null)
return false;
return b1.Name == b2.Name;
}
public int GetHashCode(Person p) => p.NameGetHashCode();
}
class PersonAgeEqualityComparer :IEqualityComparer<Person>
{
public bool Equals(Person b1, Person b2)
{
if (ReferenceEquals(b1, b2))
return true;
if (b2 is null || b1 is null)
return false;
return b1.Age == b2.Age;
}
public int GetHashCode(Person p) => p.AgeGetHashCode();
}
IEquatable<T>
IEquatable<T> 是 C#
中用于比较对象相等性的泛型接口。它定义了一个名为 Equals
的方法,用于比较对象与另一个对象的相等性。
通过实现 IEquatable<T>
接口,你可以在类中自定义对象相等性的比较逻辑。这使得你的类更具灵活性,可以根据你的需求来确定两个对象是否相等。
根据MS
推荐实现了Equals
最好也实现他的操作符==
和!=
public class Person : IEquatable<Person>
{
public string SSN
{
get;
set;
}
public override bool Equals(object obj)
{
return this.Equals(obj as Person); // 调用内部的对比即可
}
public bool Equals(Person other)
{
if (other == null)
return false;
// Optimization for a common success case.
if (ReferenceEquals(this, other))
return true;
if (this.SSN == other.SSN)
return true;
else
return false;
}
public override int GetHashCode()
{
return this.SSN.GetHashCode();
}
public static bool operator ==(Person person1, Person person2)
{
if (((object)person1) == null || ((object)person2) == null)
return Equals(person1, person2);
return person1.Equals(person2);
}
public static bool operator !=(Person person1, Person person2)
{
return !(person1 == person2); // 使用不等于即可
}
}
后言
通过上面介绍我们了解了它们两种的使用方式,那么什么时候用IEqualityComparer<T>
什么时候用IEquatable<T>
呢?
- 当目标类你没有源代码,无法直接修改的时候请使用
IEqualityComparer<T>
- 当目标类你只需要一种对比方式可以考虑使用
IEquatable<T>
- 当目标类有多重对比方式,例如根据
A
和B
或者B
和C
等多重属性进行对比,你可以定义多个IEqualityComparer<T>
- 当然两种方式可以共存,根据需要使用