==、Equals、ReferenceEquals

427 阅读3分钟

C#中的四种判等方法

public static bool operator==(MyClass left, MyClass right);

public static bool ReferenceEquals(object left, object right);
public static bool Equals(object left, object,right);
public virtual bool Equals(object right);

1. == (相等操作符)

int a = 3;
int b = 3;

Console.WriteLine(a == b);  //True

object objA = (object)a;
object objB = (object)b;

Console.WriteLine(objA == objB);   //False

值类型的相等性:对于内置值类型,如果操作数的值相等,等于运算符 == 返回 true,否则返回 false 。

Test t1 = new Test("user");
Test t2 = new Test("user");
Console.WriteLine(t1 == t2);  //False

string s1 = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
string s2 = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });

Console.WriteLine(s1 == s2);  //True

引用类型的相等性(string除外):默认情况下,如果两个引用类型引用同一个对象,则这两个操作符相等返回 true,否则返回 false。
string 是一种特殊的引用类型,在C#语言中,重载了Object对象的相等操作符,所以string的比较是比较值。


2. ReferenceEquals是Object中的一个静态方法

它的源码如下所示:

public static bool ReferenceEquals (Object objA, Object objB) {
    return objA == objB;
}

这个函数的作用其实从名字中就可以看出,即判断两个引用类型的对象是否指向同一个地址,由于已经知道了等号操作符的作用,从objA == objB 就可以推断出该函数是对对象的应用进行比较。

需要注意,ReferenceEquals只能用于引用类型,对于值类型的操作都会返回false,如下示例,

int a = 1;
int b = 1;

bool result1 = Object.ReferenceEquals(a, b);//output: False
bool result2 = Object.ReferenceEquals(a, a);//output: False

3. 实例Equals函数

// Returns a boolean indicating if the passed in object obj is 
// Equal to this.  Equality is defined as object equality for reference
// types and bitwise equality for value types using a loader trick to
// replace Equals with EqualsValue for value types).

public virtual bool Equals(Object obj)
{
    return RuntimeHelpers.Equals(this, obj);
}

对于值类型来说,实例Equals函数与 == 操作符是等价的,都是比较两个对象的值。

对于引用类型来说,如果指定的对象等于当前对象(意为指向同一个地址),则为 true,否则为 false。 继承了Object的类型默认使用Object中的Equals函数,为了满足不同的需求,我们也可以重写该方法。


class Point
{
   protected int x, y;

   public Point() : this(0, 0)
   { }

   public Point(int x, int y)
   {
      this.x = x;
      this.y = y;
   }
 
   public override bool Equals(Object obj)
   {
      //Check for null and compare run-time types.
      if ((obj == null) || ! this.GetType().Equals(obj.GetType())) 
      {
         return false;
      }
      else { 
         Point p = (Point) obj; 
         return (x == p.x) && (y == p.y);
      }   
   }

   public override int GetHashCode()
   {
      return (x << 2) ^ y;
   }

   public override string ToString()
   {
        return String.Format("Point({0}, {1})", x, y);
   } 
}


4. 静态Equals函数

直接上源码

public static bool Equals(Object objA, Object objB) 
{
   if (objA == objB) {
        return true;
   }
   if (objA == null || objB == null) {
        return false;
   }
   return objA.Equals(objB);
}
    1. 将两个参数转换为object类,如果是值类型,就将其装箱成Object,成为引用类型,然后通过 == 运算符对比栈中的 指向内存的地址。
int a = 3;
int b = 3;

object objA = (object)a;
object objB = (object)b;
            
Console.WriteLine(objA == objB);   //False
    1. 进行非空验证
    1. 调用 objA 对象的 Equals 方法,需要注意!这里调用的并不是 Object 类的 Equals 方法 而是当前传递过来的对象类 类型的 Equals 方法!