5种平等检查方式.net ..为什么? 和哪个使用?
学习.net(通过C#)我发现了5种方法来检查对象之间的平等。
- ReferenceEquals()方法。
- 虚拟Equals()方法。 (System.Object的)
- 静态Equals()方法。
- 从IEquatable接口的Equals方法。
- 比较运算符==。
我的问题是:
- 为什么有这么多的Equals()方法和比较运算符?
- 哪一个虚拟Equals()或IEquatable的Equals()sholud被使用..(说如果我们使用我们自己的集合类)
1 – 引用等于检查两个引用typesvariables(类,而不是结构)是否被引用到相同的内存地址。
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 – 在检查中存在空值时,使用静态等式方法来处理问题。 想象一下,例如:
TestClass o1 = null; var o2 = new TestClass{property1 = 1, property2 = 2}
如果你尝试这个:
o1.Equals(o2);
你将得到一个NullReferenceException,因为o1指向没有。 为了解决这个问题,你这样做:
的Object.Equals(O1,O2);
此方法准备处理空引用。
4 – IEquatable接口由.Net提供,因此您不需要在Equals方法中进行强制转换。 如果编译器发现你已经在一个类中实现了你试图检查相等的types的接口,那么它将优先于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意思相同,它检查两个variables是否指向相同的内存地址。 这个问题是,这个操作员可以被覆盖以执行其他types的检查。 例如,在string中,它检查两个不同的实例是否相等。
这是一个有用的链接,以更好地理解.Net中的平等:
- CodeProject上
ReferenceEquals()方法。
这用于testing两个给定的variables是否指向同一个对象(符号引用)。 它实际上相当于((object)a) == ((object)b)
。 如果您重写比较运算符( ==
),则ReferenceEquals
维护一种访问默认行为的方法。
但是 ,如果你正在处理一个值types(例如一个结构),那么这将始终返回false 。 这是因为比较框将每个值types都绑定到一个新对象,所以引用自然不会相等。
虚拟Equals()方法。 (System.Object的)
这是在语义上比较两个对象(任何types)的默认方式。 每个class级都会按照自己的select重写。 默认情况下,它相当于一个基本上比较内存引用的CLR调用( InternalEquals )。
请注意,如果两个对象对于Equals()
返回true,则每个对象上的GetHashCode()
必须相等 。 但是,如果两个对象的哈希码是等价的(即obj1.GetHashCode() == obj2.GetHashCode()
),这并不意味着Equals()
是真的。
您的类通常应该实现Equals
和GetHashCode
作为区分类实例的方法,并且必须实现这个或==
运算符(理想情况下都是),如果它是值types的话。
请注意,对于值types,默认的Equals
行为是ValueType.Equals()
,如果您在Reflector中查看(或读取MSDN描述 ),则使用reflection来比较两个值实例的成员。
静态Equals()方法。
这相当于return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)))
,其中每个types都转换为Object
进行testing。 我的testing显示,重载的比较运算符被忽略,但是如果对象不是null并且不是相同的引用,则将使用Equals
方法。 因此, a.Equals(b)
不一定等于a.Equals(b)
object.Equals(a, b)
(对于((object)a) == ((object)b)
或a或b为null的情况。
从IEquatable接口的Equals方法。
IEquatable为您提供了一种方法,可以将特定对象同类的实例进行比较。 说了你的Equals
方法应该以同样的方式处理行为 :
如果实现Equals,则还应该重写Object.Equals(Object)和GetHashCode的基类实现,以使其行为与IEquatable.Equals方法的行为一致
不过你应该实现IEquatable :
为了处理一个类的对象将被存储在一个数组或一个通用的集合对象中的可能性,实现IEquatable是一个好主意,这样对象可以很容易地被识别和操作。
比较运算符==
当两个对象都是相同的引用时,比较运算符默认返回true。
不build议重写比较运算符,除非您正在处理值types (在这种情况下,build议使用Equals
方法),或者您通常使用一个不可变的引用types(比如string
)进行比较。 始终实现!=
同时(事实上,我得到一个requires a matching operator '!=' to also be defined
错误,如果我不)。
资源:
- http://blogs.msdn.com/b/vijaysk/archive/2008/03/19/object-referenceequals-valuevar-valuevar-will-always-return-false.aspx
- InternalEquals的实现在哪里(object objA,object objB)
- http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
- http://msdn.microsoft.com/en-us/library/2dts52z7.aspx
- http://msdn.microsoft.com/en-us/library/ms131190.aspx
- http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
- http://msdn.microsoft.com/en-us/library/ms182276(VS.80).aspx
每个版本的平等是略有不同的。
ReferenceEquals
testing引用是否相等。
virtual Equals
默认检查类types的引用相等性和结构types的值相等性。 如果需要,可以重写定义不同的等式。 并应该为值types重写。
static Equals
只是调用virtual Equals
,但也允许null
参数。
IEquatable<T>.Equals
是virtual Equals
的通用/types安全的等价物。
operator==
旨在像默认的virtual Equals
,意味着类types的引用相等(除非该类也覆盖其他运算符)。 值types也应该被覆盖。
如果您编写自己的集合类,则使用IEqualityComparer<T>
,默认为EqualityComparer<T>.Default
。 不要直接使用任何相等的比较。
对于基元,使用==运算符。
在.NET框架提供的大多数对象中,您创build.Equals()方法的任何自定义对象,而==运算符将仅检查两个对象是否引用堆中的同一对象。
IEquatable接口的目的是重写.Equals()方法来改变它的行为,从检查引用相等来检查值是否相等。 System.Stringtypes是实现此接口的内置.NET对象的示例。
.ReferenceEquals()方法为覆盖标准.Equals()方法的开发人员提供了一种方法,以便仍然可以检查两个对象以进行引用相等。