Разница между оператором == и методом Equals () в C #? - PullRequest
17 голосов
/ 02 марта 2012

В чем разница между == и Equals() с примером? Я знаю, что == используется для сравнения оператора и Equals() метод используется для сравнения содержимого строки. Так что я попытался

// first example
string s1 = "a";
string s2 = "a";
Console.Write(a.Equals(s2)); // returns true, but if I assign "b" to s2,
                             // then result will be false

// second example
string s1 ="a";
string s2 ="a";
Console.Write(s1 == s2);     // returns true

Как это так? Оба - разные ссылки на объекты. Предположим, мы считаем, что это ссылки. Но я пытался использовать вот так

string s1 = new string("ab");
string s2 = new string("ab");

Я получаю сообщение об ошибке компиляции, которое не может преобразовать строку в символ

Ответы [ 3 ]

22 голосов
/ 02 марта 2012

Есть несколько вещей, происходящих.Во-первых, в этом примере:

string s1 = "a";
string s2 = "a";
Console.WriteLine(s1 == s2);

Вы утверждаете, что:

Обе являются разными ссылками на объект.

Это не так из-за интернирование строк .s1 и s2 являются ссылками на один и тот же объект.Спецификация C # гарантирует, что - из раздела 2.4.4.5 спецификации C # 4:

Когда два или более строковых литерала, которые эквивалентны в соответствии с оператором равенства строк (§7.10.7), появляются вВ той же программе эти строковые литералы ссылаются на один и тот же экземпляр строки.

Таким образом, в этом конкретном случае вы все равно получите «true», даже если вы напечатаете object.ReferenceEquals(s1, s2), или если вы сделали это, используя сравнение истинных опорных идентификаторов с ==:

object s1 = "a";
object s2 = "a";
Console.WriteLine(s1 == s2); // Still prints True due to string literal interning

Однако, даже если эти были ссылками на отдельные объекты, == является перегруженным для string.Перегрузка является решением времени компиляции - используемая реализация зависит от типов операндов времени компиляции.Например:

string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a == b); // Uses string's implementation, prints True

object c = a;
object d = b;
Console.WriteLine(c == d); // Reference identity comparison, prints False

Сравните это с object.Equals(object), который является виртуальным методом.Как это бывает, String перегружает этот метод , а также , но важно, что он переопределяет его.Поэтому, если мы изменим наш код на:

string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a.Equals((object) b));

object c = a;
object d = b;
Console.WriteLine(c.Equals(d));

..., тогда оба вызова метода в скомпилированном коде будут просто равны object.Equals(object), но они будут все еще , и оба выведут Trueиз-за полиморфизма: будет использоваться реализация в String.

Вот как будет выглядеть вызов перегруженного метода :

string a = new string('x', 1);
string b = new string('x', 1);
Console.WriteLine(a.Equals(b)); // Calls string.Equals(string)
7 голосов
/ 02 марта 2012

Цитата из документации Равно :

Реализация по умолчанию Equals поддерживает ссылочное равенство для ссылочные типы и битовое равенство для типов значений. Ссылка равенство означает, что ссылки на объекты, которые сравниваются, относятся к тот же объект. Побитовое равенство означает, что сравниваемые объекты имеют то же двоичное представление.

И оператор == :

Для предопределенных типов значений оператор равенства (==) возвращает true, если значения его операндов равны, иначе ложно. Для справки типы, отличные от string, == возвращает true, если два его операнда ссылаются на тот же объект. Для типа строки == сравнивает значения строки.

Теперь вернемся к вашему вопросу: почему s1 == s2 возвращает true? Струны - это особые звери в .NET. Они представляют собой неизменяемые ссылочные типы. Они интернированы в .NET. Это означает, что если у вас есть 2 строковые константы с одинаковым значением, они будут ссылаться на один и тот же экземпляр объекта во время выполнения.

Цитата из документации :

Общеязыковая среда выполнения сохраняет хранилище строк, поддерживая таблица, называемая внутренним пулом, которая содержит одну ссылку на каждая уникальная буквенная строка, объявленная или созданная программно в ваша программа. Следовательно, экземпляр литеральной строки с конкретное значение существует только один раз в системе.

2 голосов
/ 02 марта 2012

Ты думаешь, похоже на Java-esque. В Java оператор == не может быть настроен, поэтому для ссылочных типов это всегда означает равенство ссылок, в то время как это означает равенство значений для примитивных типов. С другой стороны, Equals предназначен для проверки равенства значений в ссылочных типах.

В C # все по-другому. И Equals, и == могут иметь пользовательские реализации. Разница в том, что Equals - это виртуальный (экземплярный) метод, а operator== - статический. Кроме того, они могут вести себя точно так же.

По умолчанию и Equals, и == проверяют равенство ссылок для ссылочных типов и равенство значений для типов значений. Однако для string оба настроены для проверки равенства значений.

...