2010-09-16 6 views
5

Меня поразила странная «асимметрия» на C#, которую я действительно не понимаю. См. Следующий код:Object.Equals является виртуальным, но Object.operator == не использует его в 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, но второе утверждение не выполняется.

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

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

+0

Я нашел [ответ] (http://stackoverflow.com/questions/1766492/c-overloading-operator-versus-equals/1849288#1849288) на мой вопрос и в другом потоке. Кажется, что 'object.operator ==' использует 'object.ReferenceEquals', но' string.operator == 'использует' object.Equals'. Это противоречит интуиции, потому что 'object.Equals' является виртуальным, поэтому его можно использовать уже в' object.operator == '. – wigy

ответ

7

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

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

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

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

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

+0

Хммм. Итак, вы говорите, что Object.operator == определяется с помощью ReferenceEquals, тогда как String.operator == определяется с помощью Equals. Разве это не так красиво и интуитивно? – wigy

+1

@ wigy: В большинстве случаев это работает очень хорошо, но, конечно, такие ситуации, как ваш пример, где вы можете ожидать, что сравнение будет определено во время выполнения. Это, конечно, более интуитивно, чем, например, в C++ и Java, где вы не можете надежно использовать оператор == на строках вообще. В VB оператор = определяет сравнение во время выполнения, что больше соответствует тому, как работает VB, но это дает несколько других ситуаций, когда это может вас удивить. В C# можно определить из кода точно, какое сравнение будет использоваться, что больше соответствует тому, как работает C# в целом. – Guffa

+0

Спасибо, Guffa. Я знаю, что это лучше, чем C, Java или VB. Операторы C++ могут быть виртуальными, поэтому у вас есть разные проблемы.Вот почему большинство стандартов кодирования на C++ используют условия Yoda, такие как 'if (5 == something) {...}' Из вашего ответа я понял, что дизайнеры фреймворков считали, что ReferenceEquals более интуитивно понятен для некоторых из кодеров, но фиксированная строка .оператор == с другой стороны. – wigy

6

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

+2

Также стоит отметить, что для полноты, что static 'object.Equals (apple, orange)' в этом случае вернет true. 'object.Equals' сначала использует' == 'для проверки равенства ref, и если это не удается, он будет использовать перегруженный' apple.Equals (оранжевый) '(если предположить, что' apple' и 'orange' не' null'). – LukeH

+0

Я понимаю, что я использую 'static bool Object.operator == (Object, Object)'. Но я до сих пор не понимаю, почему это не вызывает «Object.Equals (Object)». Поскольку это виртуально, в конце будет вызываться правильный 'String.Equals (Object)'. – wigy