在 .NET 中使用 C# 时,对象比较(判等)可以通过多种方式进行,主要包括引用相等性比较和值相等性比较。理解这些不同的比较方法对于编写准确和高效的代码至关重要。值类型变量判断就是比较值是否相等,而引用类型的对象判断是否相等,一般是判断指定的对象是否是相同的实例。
1、Object.ReferenceEquals(static)
Object.ReferenceEquals
判断两个对象引用是否指向内存中的同一位置,若是使用Object.ReferenceEquals
对值类型变量进行判等,'Object.ReferenceEquals‘ 总是返回False
,需要特别注意一下。ReferenceEqual
的方法签名及方法体,如下:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static bool ReferenceEquals(object objA, object objB)
{
return (objA == objB);
}
从代码中可以看出传入值类型参数,会装箱成object类型,由于对象不是相同的实例,所以就会总是返回False
。
例如:
代码语言:javascript复制using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
Object obj1 = new Object();
Object obj2 = obj1;
bool areEqual = Object.ReferenceEquals(obj1, obj2); // true
Console.WriteLine(areEqual);
Console.WriteLine(Object.ReferenceEquals(11, 11));//false
Console.ReadKey();
}
}
}
2、Object.Equals(static)
Object.Equals
用于比较两个对象的值或状态是否相等。可以重写 Equals 方法来定义自定义类型的相等逻辑。Object.Equals
的方法签名及方法体,如下:
public static bool Equals(object objA, object objB)
{
return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}
例如:
代码语言:javascript复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = 10;
bool areEqual = Object.Equals(a, b); // true
Console.WriteLine(areEqual);
object obj1 = new object();
object obj2 = new object();
areEqual = Object.Equals(obj1, obj2); // 返回 false,因为 obj1 和 obj2 指向不同的对象
Console.WriteLine(areEqual);
Console.ReadKey();
}
}
}
3、Operator操作符(==)
==
运算符可以用于比较对象。对于引用类型,默认行为是比较引用,但可以重载这些运算符来实现自定义的值比较。如下代码:
//添加下面代码到ThreeDPoint类定义之前
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);
}
需要注意的是,运算符 ==
的重写中的常见错误是,重写的方法内还使用 (a == b)、(a == null) 或 (b == null) 来检查引用相等性。这会调用重载的运算符 ==
,从而导致无限循环。应使用 ReferenceEquals
或将类型强制转换为 Object
来避免无限循环。
4、Instance.Equals
实例对象的Equals
方法,这个其实和第二种Object.Equals(static)
类似,只是参数只有一个,但是这个方法是在class
内部继承Object
的,是可以进行重写的。CLR会要求所有的类型都派生自Object
,每个class
内部都可以重写这个方法,如下:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public override bool Equals(object obj)
{
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;
}
}