重载相等运算符

仅重载相等运算符是不够的。在不同的情况下,可以调用以下所有内容:

  1. object.Equalsobject.GetHashCode
  2. IEquatable<T>.Equals(可选,允许避免拳击)
  3. operator ==operator !=(可选,允许使用运算符)

当覆盖 Equals 时,GetHashCode 也必须被覆盖。在实现 Equals 时,有许多特殊情况:与不同类型的对象进行比较,与自我对比等。

当未覆盖时 Equals 方法和 == 运算符对类和结构的行为不同。对于类,只比较引用,对于结构,通过反射比较属性的值,这会对性能产生负面影响。== 不能用于比较结构,除非它被覆盖。

通常,相等操作必须遵守以下规则:

  • 不得抛出异常
  • 反身性:A 总是等于 A(某些系统中的 NULL 值可能不正确)。
  • Transitvity:如果 A 等于 BB 等于 C,则 A 等于 C
  • 如果 A 等于 B,则 AB 具有相同的哈希码。
  • 继承树独立性:如果 BC 是从 Class1 继承的 Class2 的实例:Class1.Equals(A,B) 必须始终返回与调用 Class2.Equals(A,B) 相同的值。
class Student : IEquatable<Student>
{
    public string Name { get; set; } = "";

    public bool Equals(Student other)
    {
        if (ReferenceEquals(other, null)) return false;
        if (ReferenceEquals(other, this)) return true;
        return string.Equals(Name, other.Name);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;

        return Equals(obj as Student);
    }

    public override int GetHashCode()
    {
        return Name?.GetHashCode() ?? 0;
    }

    public static bool operator ==(Student left, Student right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Student left, Student right)
    {
        return !Equals(left, right);
    }
}