Object.Equals является виртуальным, но Object.operator== не использует его в C#?

Меня поразила странная "асимметрия" в C#, которую я не очень понимаю. Смотрите следующий код:

using System;
using System.Diagnostics;
namespace EqualsExperiment
{
    class Program
    {
        static void Main(string[] args)
        {
            object apple = "apple";
            object orange = string.Format("{0}{1}", "ap", "ple");
            Console.WriteLine("1");
            Debug.Assert(apple.Equals(orange));
            Console.WriteLine("2");
            Debug.Assert(apple == orange);
            Console.WriteLine("3");
        }
    }
}

Это может быть очевидно для всех вас.NET-гуру, но 2-е утверждение не удается.

В Java я узнал, что == является синонимом для чего-то под названием Object.ReferenceEquals здесь. В C# я думал, что Object.operator== использует Object.Equals, который является виртуальным, поэтому он переопределяется в классе System.String.

Может кто-нибудь объяснить, почему 2-й assert терпит неудачу в C#? Какие из моих предположений плохи?

2 ответа

Решение

== оператор не является синонимом, это оператор, который определен для разных типов.

== оператор определен для строк, а затем он действительно использует Equals метод:

public static bool operator ==(string a, string b) {
  return Equals(a, b);
}

Однако, в вашем коде вы не используете оператор для строк, вы используете его для объектов, так что вы получите == оператор, определенный для объектов, который использует ReferenceEquals сделать сравнение.

Какая перегрузка используемого оператора определяется во время компиляции, поэтому перегрузку определяет тип переменных, а не фактический тип объектов, на которые указывают переменные.

Операторы определяются как статические методы, поэтому они не могут участвовать в полиморфизме. Таким образом, ваш второй утверждение использует определение == за object (поскольку ваши переменные объявлены как object), который проверяет только ссылочное равенство. Если переменные были объявлены как string, == перегрузка для string был бы использован, и второй утверждал бы успешно.

Другие вопросы по тегам