考虑以下简单程序。
using System;
namespace CompareClasses
{
class A
{
public override bool Equals(object obj)
{
Console.WriteLine("\nHi, It is me A!");
return base.Equals(obj);
}
}
class Program
{
static void Main(string[] args)
{
A a1 = new A();
A a2 = new A();
A a3 = a1;
Console.WriteLine("compare a1 to a2: {0}", Equals(a1, a2));
Console.WriteLine("compare a1 to a3: {0}", Equals(a1, a3));
}
}
}
其输出如下
Hi, It is me A!
compare a1 to a2: False
compare a1 to a3: True
所以问题是为什么消息嗨,这是我!只显示一次?
虽然如果要查看MSIL代码,我们可以看到静态方法Equals
被调用两次。
IL_000f: ldstr "compare a1 to a2: {0}"
IL_0014: ldloc.0
IL_0015: ldloc.1
IL_0016: call bool [mscorlib]System.Object::Equals(object,
object)
IL_001b: box [mscorlib]System.Boolean
IL_0020: call void [mscorlib]System.Console::WriteLine(string,
object)
IL_0025: nop
IL_0026: ldstr "compare a1 to a3: {0}"
IL_002b: ldloc.0
IL_002c: ldloc.2
IL_002d: call bool [mscorlib]System.Object::Equals(object,
object)
IL_0032: box [mscorlib]System.Boolean
IL_0037: call void [mscorlib]System.Console::WriteLine(string,
答案 0 :(得分:5)
因为object.Equals(obj1, obj2)
将首先使用object.ReferenceEquals
来检查两个对象是否都是相同的引用。这对于a1和a3都是如此。
来自MSDN:
静态Equals(Object,Object)方法指示是否两个 对象,objA和objB是相等的。它还使您可以测试对象 其值为null,表示相等。它比较了objA和objB 平等如下:
ReferenceEquals
方法。另外objA
和objB
都是null
,则该方法返回true。它确定objA
或objB
是null
。如果是这样,则返回false。如果两个对象不表示相同的对象引用,并且都不为null,则objA.Equals(objB)
并返回结果。这意味着如果objA
覆盖Object.Equals(Object)
方法,则会调用此覆盖。这就是为什么只有这会调用你的覆盖Equals
:
Console.WriteLine("compare a1 to a2: {0}", Equals(a1, a2));
因为两个对象都是不同的引用,并且两者都不为空。
答案 1 :(得分:3)
您正在调用Program.Equals(object, object)
(由于Program
不会覆盖隐式Equals
基类的object
,因此会有效调用System.Object.Equals
。它有一个早期退出参考等同物:
if(ReferenceEquals(o1, o2)) { return true; }
else return o1.Equals(o2); // only here get's your override bool Equals(object other) called
(与上面类似。显然也会检查空值)
答案 2 :(得分:1)
您正在调用Object上的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);
}
第一次在比较a1和a2时调用此方法时,您使用的是两个不同的A实例。因此,您的方法将在返回objA.Equals(objB)上面的最后一行调用。
第二次调用此方法时,您将传递相同的A实例。将a3设置为等于a1。因此,if(objA == objB)行将为true,因此它只会在该点处快捷方式并返回true,并且永远不会调用被覆盖的方法。