为什么方法Equals只调用一次进行两次比较?

Vla*_*cow 1 c# equals

考虑以下简单程序.

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

其输出如下

Hi, It is me A!
compare a1 to a2: False
compare a1 to a3: True
Run Code Online (Sandbox Code Playgroud)

所以问题是为什么消息嗨,这是我!只显示一次?

虽然如果要查看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,
Run Code Online (Sandbox Code Playgroud)

Tim*_*ter 5

因为object.Equals(obj1, obj2)将首先用于object.ReferenceEquals检查两个对象是否是相同的引用.a1和a3都是如此.

来自MSDN:

静态Equals(Object,Object)方法指示两个对象objA和objB是否相等.它还使您能够测试值为null的对象是否相等.它比较了objA和objB的相等性,如下所示:

  1. 它确定两个对象是否表示相同的对象引用.如果是,则该方法返回true.此测试等同于调用该ReferenceEquals方法.此外
  2. 如果两个objAobjBnull,该方法返回true.它确定是否任一objAobjBnull.如果是这样,则返回false.如果两个对象不表示相同的对象引用,并且都不为null,
  3. 它调用objA.Equals(objB)并返回结果.这意味着如果objA覆盖该Object.Equals(Object)方法,则调用此覆盖.

这就是为什么只有这个会调用你的覆盖Equals:

Console.WriteLine("compare a1 to a2: {0}", Equals(a1, a2));
Run Code Online (Sandbox Code Playgroud)

因为两个对象都是不同的引用,并且都不是null.