Разность С# между == и Equals()

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

Вот код:

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

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

Любая причина, почему это происходит?

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

> 2 == 2.0
True

> 2.Equals(2.0)
False

И для строк

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

> x.Equals(null)
NullReferenceException

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

  • == сравнивает ссылки на объекты.
  • .Equals сравнивает содержимое объекта.
  • String datatypes всегда действуют как сравнение содержимого.

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

Ответ 8

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

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

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

Фоновая информация и лето:

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

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

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

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

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

Это немного больше, чтобы писать, но, на мой взгляд, безопаснее использовать.

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

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

параметры

строка

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

b Строка

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

Возвращает Boolean

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

Ответ 9

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

Ответ 10

Добавление еще одной точки в ответ.

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

Ответ 11

Существует еще одно измерение более раннего ответа от @BlueMonkMN. Дополнительное измерение состоит в том, что ответ на вопрос о названии @Drahcir, как указано, также зависит от того, как мы достигли значения string. Чтобы проиллюстрировать:

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

Console.WriteLine("\n  Case1 - A method changes the value:");
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));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

Вывод:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

Ответ 12

Ток == в С# используется для двух разных операторов проверки равенства. Когда компилятор встречает этот токен, он проверяет, осуществил ли какой-либо из сравниваемых типов перегрузку оператора равенства или для сравнения отдельных типов комбинации (*), или для комбинации типов, к которым могут быть преобразованы оба типа. Если компилятор найдет такую ​​перегрузку, он будет использовать его. В противном случае, если два типа являются ссылочными типами, и они не являются несвязанными классами (либо они могут быть интерфейсом, либо могут быть связанными классами), компилятор будет рассматривать == как оператор сравнения ссылок. Если ни одно условие не применяется, компиляция завершится неудачно.

Обратите внимание, что некоторые другие языки используют отдельные токены для двух операторов проверки равенства. Например, в VB.NET токен = используется в выражениях исключительно для перегружаемого оператора проверки равенства, а Is используется как оператор ссылочного теста или нулевого теста. An использовать = для типа, который не переопределяет оператор проверки равенства, не будет работать, как будет пытаться использовать Is для любых целей, кроме проверки ссылочного равенства или недействительности.

(*) Типы обычно только перегружают равенство для сравнения с самим собой, но может быть полезно, чтобы типы перегружали оператор равенства для сравнения с другими конкретными типами; например, int мог бы (и IMHO должен был иметь, но не сделал) определил операторы равенства для сравнения с float, так что 16777217 не сообщил бы себя равным 16777216f. Как бы то ни было, поскольку такой оператор не определен, С# будет продвигать int до float, округляя его до 16777216f, прежде чем оператор проверки равенства увидит его; этот оператор затем видит два равных числа с плавающей запятой и сообщает о них как о равных, не подозревая о округлении, которое имело место.

Ответ 13

Действительно отличные ответы и примеры!

Я просто хотел бы добавить принципиальное различие между ними,

Операторы, такие как ==, не являются полиморфными, а Equals -

С учетом этой концепции, если вы выработаете какой-либо пример (посмотрев на ссылочный тип левой руки и правой руки и проверив/зная, действительно ли тип перегружен оператором ==, а Equals переопределены), вы наверняка получите правильный ответ.

Ответ 14

Просто как дополнение к и без того хорошим ответам: это поведение НЕ ограничено строками или сравнением различных типов чисел. Даже если оба элемента имеют тип объекта одного и того же базового типа. "==" не сработает.

На следующем скриншоте показаны результаты сравнения двух значений объекта {int}

Example From VS2017

Ответ 15

Когда мы создаем какой-либо объект, в объекте есть две части, одна из которых является контентом, а другая - ссылкой на этот контент. == сравнивает как контент, так и ссылку; equals() сравнивает только контент

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq

Ответ 16

==

Оператор == может использоваться для сравнения двух переменных любого типа, а просто сравнивает бит.

int a = 3;
byte b = 3;
if (a == b) { // true }

Примечание: в левой части int больше нулей, но здесь нас это не волнует.

int a (00000011) == byte b (00000011)

Помните == оператор заботится только о шаблоне бит в переменной.

Использовать == Если две ссылки (примитивы) относятся к одному и тому же объекту в куче.

Правила одинаковы, является ли переменная ссылкой или примитивом.

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c истинно a == b является ложным

бит-шаблон одинаковый для a и c, поэтому они равны с использованием ==.

Равно():

Используйте метод equals(), чтобы увидеть , если два разных объекта равны.

Например, два разных объекта String, которые оба представляют символы в "Jane"

Ответ 17

Единственное различие между Equal и == заключается в сравнении типов объектов. в других случаях, таких как ссылочные типы и типы значений, они почти одинаковы (либо оба являются поразрядным равенством, либо оба являются ссылочным равенством).

объект: Равновесие: побитовое равенство ==: ссылочное равенство

string: (equals и == одинаковы для строки, но если одна из строк изменилась на объект, результат сравнения будет другим) Равновесие: побитовое равенство ==: поэтапное равенство

Подробнее см. здесь.