关于实现等式操作符(==)的相关信息,请参考:[Equals 与等式操作符(==)的实现指南]。
遵循 Object.Equals 方法中被定义的约定,如下所示:
下列代码范例示范了 Equals 方法的实现、重载调用,以及重载。
下列代码范例包含了对于默认 Equals 方法实现的两个调用。
Imports System Class SampleClass Public Shared Sub Main() Dim obj1 As New System.Object() Dim obj2 As New System.Object() Console.WriteLine(obj1.Equals(obj2)) obj1 = obj2 Console.WriteLine(obj1.Equals(obj2)) End Sub End Class
using System; class SampleClass { public static void Main() { Object obj1 = new Object(); Object obj2 = new Object(); Console.WriteLine(obj1.Equals(obj2)); obj1 = obj2; Console.WriteLine(obj1.Equals(obj2)); } }
前述代码的输出如下:
False True
下列代码范例说明了重载 Equals 方法来提供值等式的一个 Point 类以及 Point 的派生类 Point3D。因为 Point 类的 Equals 重载是最先在继承链中被用来引入值等式的重载,所以基类(派生自 Object 并且检查参考等式)的 Equals 方法不会被调用。但是,Point3D.Equals 会调用 Point.Equals,因为 Point 是以提供值等式的风格来实现 Equals 的。
Namespace Examples.DesignGuidelines.EqualsImplementation Public Class Point Protected x As Integer Protected y As Integer Public Sub New (xValue As Integer, yValue As Integer) Me.x = xValue Me.y = yValue End Sub Public Overrides Overloads Function Equals(obj As Object) As Boolean If obj Is Nothing OrElse Not Me.GetType() Is obj.GetType() Then Return False End If Dim p As Point = CType(obj, Point) Return Me.x = p.x And Me.y = p.y End Function Public Overrides Function GetHashCode() As Integer Return x Xor y End Function End Class Public Class Point3D Inherits Point Private z As Integer Public Sub New (xValue As Integer, yValue As Integer, zValue As Integer) MyBase.New(xValue, yValue) Me.z = zValue End Sub Public Overrides Overloads Function Equals(obj As Object) As Boolean Return MyBase.Equals(obj) And z = CType(obj, Point3D).z End Function Public Overrides Function GetHashCode() As Integer Return MyBase.GetHashCode() Xor z End Function End Class End Namespace
using System; namespace Examples.DesignGuidelines.EqualsImplementation { class Point: object { protected int x, y; public Point(int xValue, int yValue) { x = xValue; y = yValue; } public override bool Equals(Object obj) { // 检查 null 值并且比较运行时类型。 if (obj == null || GetType() != obj.GetType()) return false; Point p = (Point)obj; return (x == p.x) && (y == p.y); } public override int GetHashCode() { return x ^ y; } } class Point3D: Point { int z; public Point3D(int xValue, int yValue, int zValue) : base(xValue, yValue) { z = zValue; } public override bool Equals(Object obj) { return base.Equals(obj) && z == ((Point3D)obj).z; } public override int GetHashCode() { return base.GetHashCode() ^ z; } } }
Point.Equals 方法检查到 obj 参量不是 null 值并且它还引用了与这个对象相同的一个类型实例。如果其中一种检查失败,方法返回 false 值。Equals 方法使用 GetType 方法来检查这两个对象的运行时类型是否完全相同。注意:typeof(在 Visual Basic 中是 TypeOf)在这里没有被使用,因为它返回静态的类型。如果方法已经被用来检查 obj 是否被替换成 Point,那么在 obj 是由 Point 所派生的一个实例的情况下,检查将会返回 true,尽管 obj 以及当前实例不是相同的运行时类型。已经被核实的那两个对象就是相同的类型,方法把 obj 转换成 Point 类型并且返回两个对象实例变量的对比结果。
在 Point3D.Equals 中,被继承的 Equals 方法在任何操作被完成之前被调用。被继承的 Equals 方法会核实那个 obj 不是 null、那个 obj 是与该对象一样的相同实例,并且被继承的实例变量相匹配。只在被继承的 Equals 返回 true 值的时候,方法才能够对比被引入到派生类中的实例变量。尤其是,对于 Point3D 的转换并没有被执行,除非已经检测到 obj 是 Point3D 类型或者是一个派生自 Point3D 的类。
在前面的范例中,等式操作符(==)被用来对比单独的实例变量。在有些情况下,它适合于使用 Equals 方法在 Equals 的一个实现中对比实例变量,如下代码范例所示。
Imports System Class Rectangle Private a, b As Point Public Overrides Overloads Function Equals(obj As [Object]) As Boolean If obj Is Nothing Or Not Me.GetType() Is obj.GetType() Then Return False End If Dim r As Rectangle = CType(obj, Rectangle) ' 使用 Equals 来对比实例变量。 Return Me.a.Equals(r.a) And Me.b.Equals(r.b) End Function Public Overrides Function GetHashCode() As Integer Return a.GetHashCode() ^ b.GetHashCode() End Function End Class
using System; class Rectangle { Point a, b; public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; Rectangle r = (Rectangle)obj; // 使用 Equals 来对比实例变量。 return a.Equals(r.a) && b.Equals(r.b); } public override int GetHashCode() { return a.GetHashCode() ^ b.GetHashCode(); } }
在有些编程语言中(如 C#),操作符重载是被支持的。在一个类型重载了等式操作符(==)的时候,它应该同样重载 Equals 方法来提供相同的功能。这典型地通过在被重载的等式操作符(==)术语中编写 Equals 方法而被完成,如下代码范例所示。
public struct Complex { double re, im; public override bool Equals(Object obj) { return obj is Complex && this == (Complex)obj; } public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } public static bool operator ==(Complex x, Complex y) { return x.re == y.re && x.im == y.im; } public static bool operator !=(Complex x, Complex y) { return !(x == y); } }
因为 Complex 是一个 C# 结构(一个值类型),并且已知没有任何类将会从 Complex 那里被派生。因此,Equals 方法不需要对比每个对象的 GetType 结果。代替它的是使用 is 操作符来检查 obj 参数的类型。