在学习.net(通过c#)时,我找到了5种方法来检查对象之间的相等性。
我的问题是:
答案 0 :(得分:29)
ReferenceEquals()方法。
这用于测试两个给定变量是否指向同一个对象(符号引用)。它实际上相当于((object)a) == ((object)b)
。如果覆盖比较运算符(==
),则ReferenceEquals
会保留一种访问默认行为的方法。
然而,如果您正在处理值类型(例如结构),那么这个will always return false。这是因为比较框每个值都为新对象的类型,所以引用自然不会相等。
虚拟Equals()方法。 (System.Object的)强>
这是在语义上比较两个对象(任何类型)的默认方式。每个班级都会根据他们的选择覆盖。默认情况下,它等同于CLR调用(InternalEquals),它基本上比较了内存引用。
注意,如果Equals()
的两个对象返回true,则每个GetHashCode()
obj1.GetHashCode() == obj2.GetHashCode()
都返回Equals()
。但是,如果两个对象的哈希码值相等(即Equals
),则不表示GetHashCode
为真。
您的类通常应实现==
和Equals
作为区分类实例的方法,并且如果它是值类型,则必须实现此操作或ValueType.Equals()
运算符(理想情况下都是)。
注意,对于值类型,默认return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)))
行为是Object
的行为,如果您查看Reflector(或读取must be equal),则使用反射来比较两个值实例的成员
静态Equals()方法。
这相当于Equals
,其中每种类型都转换为a.Equals(b)
进行测试。我的测试显示忽略了重载的比较运算符,但如果对象不为null且不是相同的引用,则将使用object.Equals(a, b)
方法。因此,((object)a) == ((object)b)
不一定等于Equals
(对于Equals
或a或b为空的情况。)
来自IEquatable接口的Equals方法。
IEquatable提供了一种方法,可以专门处理与同一个类的实例的比较。说了string
方法the MSDN description:
如果你实施Equals,你应该 也覆盖基类 的实现 Object.Equals(Object)和GetHashCode 这样他们的行为是一致的 与IEquatable.Equals的那个 方法
should be handling the behaviour the same way:
处理对象的可能性 类的存储将存储在数组中 或者是一个通用的集合对象,它是 实现IEquatable是一个好主意 这样物体就可以轻松实现 识别和操纵。
比较运算符==
当两个对象都是同一个引用时,默认情况下,比较运算符返回true。
它Nevertheless you should implement IEquatable覆盖比较运算符,除非您处理is not recommended(在这种情况下建议使用!=
方法)或通常不可变的引用类型按值进行比较(例如requires a matching operator '!=' to also be defined
)。始终同时实施{{1}}(事实上,如果我不这样做,我会收到{{1}}错误。)
<强>资源:强>
答案 1 :(得分:27)
1 - 引用等于检查两个引用类型变量(类,而不是结构)是否被引用到同一个内存地址。
2 - 虚拟Equals()方法检查两个对象是否相同。让我们说你有这个课程:
class TestClass{
public int Property1{get;set}
public int Property2{get;set}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
}
并从该类实例化2个对象:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
虽然这两个对象不是TestClass的同一个实例,但对o1.Equals(o2)的调用将返回true。
3 - 静态Equals方法用于在检查中存在空值时处理问题。 想象一下,例如:
TestClass o1 = null;
var o2 = new TestClass{property1 = 1, property2 = 2}
如果您尝试这样做:
o1.Equals(o2);
你会得到一个NullReferenceException,因为o1指向什么都没有。 要解决此问题,请执行以下操作:
的Object.Equals(O1,O2);
此方法准备处理空引用。
4 - IEquatable接口由.Net提供,因此您无需在Equals方法中进行强制转换。 如果编译器发现您已在类中尝试检查相等性的类中实现了接口,则它将使该方法优先于Object.Equals(Object)覆盖。 例如:
class TestClass : IEquatable<TestClass>
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TestClass))
return false;
var convertedObj = (TestClass)obj;
return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2);
}
#region IEquatable<TestClass> Members
public bool Equals(TestClass other)
{
return (other.Property1 == this.Property1 && other.Property2 == this.Property2);
}
#endregion
}
现在,如果我们这样做:
var o1 = new TestClass{property1 = 1, property2 = 2}
var o2 = new TestClass{property1 = 1, property2 = 2}
o1.Equals(o2);
被调用的方法是Equals(TestClass),在Equals(Object)之前。
5 - ==运算符通常与ReferenceEquals相同,它检查两个变量是否指向同一个内存地址。 问题是可以覆盖此运算符以执行其他类型的检查。 例如,在字符串中,它会检查两个不同的实例是否相同。
这是更好地理解.Net中的平等性的有用链接:
答案 2 :(得分:1)
每个版本的平等略有不同。
ReferenceEquals
测试参考相等性。
virtual Equals
检查类类型的引用相等性和结构类型的值相等性。如果需要,可以覆盖它以不同方式定义相等性;并且应该覆盖值类型。
static Equals
只需调用virtual Equals
,但也允许null
个参数。
IEquatable<T>.Equals
是virtual Equals
的通用/类型安全等效项。
operator==
旨在与默认的virtual Equals
类似,意味着类类型的引用相等(除非该类也覆盖其他运算符)。它也应该被重写为值类型。
如果您编写自己的集合类,请使用IEqualityComparer<T>
,默认为EqualityComparer<T>.Default
。不要直接使用任何相等比较。
答案 3 :(得分:0)
对于基元,请坚持使用==运算符。
在.NET框架中提供的大多数对象中,您创建的.Equals()方法和==运算符只会检查两个对象是否引用堆上的同一对象。
IEquatable接口的目的是覆盖.Equals()方法,以更改其行为,检查引用相等性以检查值是否相等。 System.String类型是实现此接口的内置.NET对象的示例。
.ReferenceEquals()方法为那些覆盖标准.Equals()方法的开发人员提供了一种方法,可以检查两个对象的引用相等性。