C# 中有两种不同的相等:引用相等和值相等。
值相等:是大家普遍理解的意义上的相等:它意味着两个对象包含相同的值。例如,两个值为 2 的整数具有值相等性。
引用相等:意味着要比较的不是两个对象,而是两个对象引用,且两者引用的是同一个对象。这可以通过简单的赋值来实现,如下面的示例所示:
System.Object a = new System.Object(); System.Object b = a; System.Object.ReferenceEquals(a, b); //returns true
在上面的代码中,只存在一个对象,但存在对该对象的多个引用:a 和 b。
由于它们引用的是同一个对象,因此具有引用相等性。如果两个对象具有引用相等性,则它们也具有值相等性,但是值相等性不能保证引用相等性。
若要检查引用相等性,应使用 ReferenceEquals。若要检查值相等性,请使用 Equals。
这个Equals一般指的是Object.Equals(obj)
///object的equals public virtual bool Equals(Object obj) { return RuntimeHelpers.Equals(this, obj); } ///RuntimeHelpers.Equals [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] public new static extern bool Equals(Object o1, Object o2);
ValueType中的Equals方法重写了object的equals方法。
由于 Equals 是一个虚方法,因此任何类都可以重写其实现。表示某个值(本质上可以是任何值类型)或一组值(如复数类)的任何类都应该重写 Equals。如果类型要实现 IComparable,则它应该重写 Equals。
Equals 的新实现应该遵循 Equals 的所有保证:
Equals 的新实现不应该引发异常。建议重写 Equals 的任何类同时也重写 Object.GetHashCode。除了实现 Equals(对象)外,还建议所有的类为自己的类型实现 Equals(类型)以增强性能。例如:
class Point { internal int x; internal int y; public Point(int X, int Y) { this.x = X; this.y = Y; } public override bool Equals (Object obj) { // Performs an equality check on two points (integer pairs). if (obj == null || GetType() != obj.GetType()) return false; Point p = (Point)obj; return (x == p.x) && (y == p.y); } public override int GetHashCode() { return Tuple.Create(x, y).GetHashCode(); } }
目的:通过重载运算符 == 来比较值是否相等。
默认情况下,运算符 == 通过判断两个引用是否指示同一对象来测试引用是否相等。
因此引用类型不需要实现运算符 == 就能获得此功能。当类型不可变(即实例中包含的数据不可更改)时,通过重载运算符 == 来比较值是否相等而不是比较引用是否相等可能会很有用,因为作为不可变的对象,只要其值相同,就可以将其视为相同。建议不要在非不可变类型中重写运算符 ==。
重载的运算符 == 实现不应引发异常。重载运算符 == 的任何类型还应重载运算符 !=。例如:
//add this code to class ThreeDPoint as defined previously // public static bool operator ==(ThreeDPoint a, ThreeDPoint b) { // If both are null, or both are same instance, return true. if (System.Object.ReferenceEquals(a, b)) { return true; } // If one is null, but not both, return false. if (((object)a == null) || ((object)b == null)) { return false; } // Return true if the fields match: return a.x == b.x && a.y == b.y && a.z == b.z; } public static bool operator !=(ThreeDPoint a, ThreeDPoint b) { return !(a == b); }
public class UserProperty { int? _requestHashCode; /// <summary> /// 用户ID /// </summary> public int AppUserId { get; set; } /// <summary> /// key /// </summary> public string Key { get; set; } /// <summary> /// 文本 /// </summary> public string Text { get; set; } /// <summary> /// 值 /// </summary> public string Value { get; set; } public override int GetHashCode() { if (!IsTransient()) { if (!_requestHashCode.HasValue) _requestHashCode = (this.Key + this.Value).GetHashCode(); return _requestHashCode.Value; } return base.GetHashCode(); } public override bool Equals(object obj) { if (obj == null || !(obj is UserProperty)) return false; if (Object.ReferenceEquals(this, obj)) return true; UserProperty item = (UserProperty)obj; if (item.IsTransient() || this.IsTransient()) return false; else return item.Key == this.Key && item.Value == this.Value; } public bool IsTransient() { return string.IsNullOrEmpty(this.Key) || string.IsNullOrEmpty(this.Value); } public static bool operator ==(UserProperty left, UserProperty right) { if (Object.Equals(left, null)) { return (Object.Equals(right, null)) ? true : false; } else { return left.Equals(right); } } public static bool operator !=(UserProperty left, UserProperty right) { return !(left == right); } }
Equals() 和运算符 == 的重写准则(C# 编程指南)
C#源代码