重载相等运算符
仅重载相等运算符是不够的。在不同的情况下,可以调用以下所有内容:
object.Equals
和object.GetHashCode
IEquatable<T>.Equals
(可选,允许避免拳击)operator ==
和operator !=
(可选,允许使用运算符)
当覆盖 Equals
时,GetHashCode
也必须被覆盖。在实现 Equals
时,有许多特殊情况:与不同类型的对象进行比较,与自我对比等。
当未覆盖时 Equals
方法和 ==
运算符对类和结构的行为不同。对于类,只比较引用,对于结构,通过反射比较属性的值,这会对性能产生负面影响。==
不能用于比较结构,除非它被覆盖。
通常,相等操作必须遵守以下规则:
- 不得抛出异常。
- 反身性:
A
总是等于A
(某些系统中的NULL
值可能不正确)。 - Transitvity:如果
A
等于B
,B
等于C
,则A
等于C
。 - 如果
A
等于B
,则A
和B
具有相同的哈希码。 - 继承树独立性:如果
B
和C
是从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);
}
}