C # разница между == и Equals () - PullRequest
499 голосов
/ 02 мая 2009

У меня есть условие в приложении silverlight, которое сравнивает 2 строки, по какой-то причине при использовании == возвращается false , а .Equals() возвращает true .

Вот код:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

Есть причина, почему это происходит?

Ответы [ 17 ]

398 голосов
/ 02 мая 2009

Когда == используется для выражения типа object, оно будет преобразовано в System.Object.ReferenceEquals.

Equals является просто методом virtual и ведет себя как таковой, поэтому будет использоваться переопределенная версия (которая для типа string сравнивает содержимое).

281 голосов
/ 02 мая 2009

При сравнении ссылки на объект со строкой (даже если ссылка на объект ссылается на строку), специальное поведение оператора ==, специфичное для класса строки, игнорируется.

Обычно (если не иметь дело со строками), Equals сравнивает значения , тогда как == сравнивает ссылки на объекты . Если два сравниваемых объекта ссылаются на один и тот же точный экземпляр объекта, то оба будут возвращать true, но если один объект имеет одинаковое содержимое и поступил из другого источника (это отдельный экземпляр с одинаковыми данными), только Equals будет верните истину. Однако, как отмечено в комментариях, строка - это особый случай, поскольку она переопределяет оператор ==, поэтому при работе исключительно со ссылками на строки (а не ссылками на объекты) сравниваются только значения, даже если они являются отдельными экземплярами. Следующий код иллюстрирует тонкие различия в поведении:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Вывод:

True True True
False True True
False False True
44 голосов
/ 02 мая 2009

== и .Equals зависят от поведения, определенного в фактическом типе, и фактического типа на сайте вызова. Оба являются просто методами / операторами, которые могут быть переопределены для любого типа и любого поведения, которого пожелает автор. Исходя из своего опыта, я нахожу, что люди обычно внедряют .Equals в объект, но пренебрегают реализацией оператора ==. Это означает, что .Equals будет фактически измерять равенство значений, в то время как == будет измерять, являются ли они одной и той же ссылкой.

Когда я работаю с новым типом, определение которого находится в потоке или пишу универсальные алгоритмы, я считаю, что лучшая практика заключается в следующем

  • Если я хочу сравнить ссылки в C #, я использую Object.ReferenceEquals напрямую (не требуется в общем случае)
  • Если я хочу сравнить значения, я использую EqualityComparer<T>.Default

В некоторых случаях, когда я чувствую, что использование == неоднозначно, я буду явно использовать Object.Reference в коде, чтобы устранить неоднозначность.

Эрик Липперт недавно сделал сообщение в блоге на тему, почему в CLR есть 2 метода равенства. Стоит прочитать

18 голосов
/ 15 августа 2013

Во-первых, - это разница. Для номеров

> 2 == 2.0
True

> 2.Equals(2.0)
False

А для струн

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

В обоих случаях == ведет себя более полезно, чем .Equals

13 голосов
/ 11 августа 2011

Я бы добавил, что если вы приведете ваш объект к строке, он будет работать правильно. Вот почему компилятор выдаст вам предупреждение:

Возможно непреднамеренное эталонное сравнение; чтобы получить сравнение значений, приведите левую сторону к типу 'string'

9 голосов
/ 27 ноября 2016

Насколько я понимаю, ответ прост:

  1. == сравнивает ссылки на объекты.
  2. .Equals сравнивает содержимое объекта.
  3. Типы данных String всегда действуют как сравнение содержимого.

Надеюсь, я прав и что он ответил на ваш вопрос.

9 голосов
/ 11 октября 2012

== Оператор 1. Если операнды имеют значение Типы значений и их значения равны, возвращается значение true, иначе значение false. 2. Если операндами являются ссылочные типы , за исключением строки, и оба ссылаются на один и тот же объект, он возвращает true, иначе false. 3. Если операнды имеют строковый тип и их значения равны, он возвращает true, иначе false.

.equals 1. Если операнды являются ссылочными типами, он выполняет эталонное равенство , то есть если оба ссылаются на один и тот же объект, он возвращает true, иначе false. 2. Если операнды являются типами значений, то в отличие от оператора == он сначала проверяет их тип, а если их типы совпадают, он выполняет оператор ==, в противном случае он возвращает false.

4 голосов
/ 16 ноября 2017

Поскольку статическая версия метода .Equal до сих пор не упоминалась, я хотел бы добавить это здесь, чтобы подвести итог и сравнить 3 варианта.

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

где MyString - это переменная, которая приходит из другого места в коде.

Справочная информация и подвести итог:

В Java использование == для сравнения строк не должно использоваться. Я упоминаю об этом в случае, если вам нужно использовать оба языка, а также чтобы вы знали, что использование == также может быть заменено чем-то лучшим в C #.

В C # нет практической разницы для сравнения строк с использованием метода 1 или метода 2, если оба имеют тип string. Однако, если один равен нулю, другой имеет другой тип (например, целое число) или один представляет объект, имеющий другую ссылку, то, как показывает первоначальный вопрос, вы можете столкнуться с тем, что сравнение содержимого на равенство может не дать вы ожидаете.

Предлагаемое решение:

Поскольку использование == не совсем то же самое, что .Equals при сравнении, вы можете использовать метод static String.Equals . Таким образом, если две стороны не одного типа, вы все равно будете сравнивать содержимое, а если одна будет нулевой, вы избежите исключения.

   bool areEqual = String.Equals("Somestring", MyString);  

Еще немного написать, но, на мой взгляд, безопаснее в использовании.

Вот некоторая информация, скопированная из Microsoft:

public static bool Equals (string a, string b);

Параметры

a Строка

Первая строка для сравнения или null.

b Строка

Вторая строка для сравнения или null.

Возвращает Boolean

true, если значение a совпадает со значением b; в противном случае false. Если a и b равны null, метод возвращает true.

2 голосов
/ 11 июля 2012

Добавление еще одного пункта к ответу.

.EqualsTo() метод дает вам возможность сравнить с культурой и чувствительностью к регистру.

2 голосов
/ 02 мая 2009

Я немного запутался здесь. Если тип времени выполнения Content имеет тип string, то оба == и Equals должны возвращать true. Однако, поскольку это не так, то тип контента во время выполнения не является строкой, и вызов Equals для него делает ссылочное равенство, и это объясняет, почему Equals («энергетическая атака») завершается неудачно. Однако во втором случае решение о том, какой перегруженный == статический оператор следует вызывать, принимается во время компиляции, и это решение выглядит как == (строка, строка). это говорит мне о том, что Content обеспечивает неявное преобразование в строку.

...