У меня есть условие в приложении silverlight, которое сравнивает 2 строки, по какой-то причине, когда я использую ==
его, возвращает false, а .Equals()
возвращает true .
Вот код:
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
// Execute code
}
if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
// Execute code
}
Есть причина, почему это происходит?
==
, но операторы не являются полиморфными. В этом коде==
оператор вызывается для типаobject
, который выполняет сравнение идентификаторов вместо значения один.==
перегрузку на основе типа операндов во время компиляции.Content
Свойствоobject
. Операторы не являются виртуальными, поэтому==
вызывается реализация по умолчанию для сравнения ссылок. С Equals вызов переходит к виртуальному методуobject.Equals(object)
;string
переопределяет этот метод и выполняет порядковое сравнение содержимого строки. См. Msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx и referenceource.microsoft.com/#mscorlib/system/string.cs,507 .==
имеет тип времени компиляции,object
а правая часть имеет тип времени компиляцииstring
, то компилятор C # должен выбрать (в данном случае проблематично) перегрузкуoperator ==(object, object)
; но он будет выдавать предупреждение во время компиляции , что это может быть НЕПРЕДВИДЕННЫМ. Так что читайте предупреждения во время компиляции! Чтобы исправить проблему и по-прежнему использовать==
, приведите левую сторону кstring
. Если я правильно помню, текст предупреждения предлагает именно это.Ответы:
Когда
==
используется в выражении типаobject
, оно разрешается вSystem.Object.ReferenceEquals
.Equals
является простоvirtual
методом и ведет себя как таковой, поэтому будет использоваться переопределенная версия (которая дляstring
типа сравнивает содержимое).источник
object
тип (обратите внимание на моноширинный шрифт) технически подразумевается как «выражение типаSystem.Object
». Он не имеет ничего общего с типом времени выполнения экземпляра, на который ссылается выражение. Я думаю, что утверждение «пользовательские операторы обрабатываются какvirtual
методы» чрезвычайно вводит в заблуждение. Они обрабатываются как перегруженные методы и зависят только от типа операндов во время компиляции. Фактически, после вычисления набора пользовательских операторов-кандидатов, оставшаяся часть процедуры привязки будет точно алгоритмом разрешения перегрузки методаvirtual
разрешение метода зависит от фактического типа времени выполнения экземпляра, в то время как это полностью игнорируется в разрешении перегрузки оператора, и это действительно весь смысл моего ответа.При сравнении ссылки на объект со строкой (даже если ссылка на объект ссылается на строку), специальное поведение
==
оператора, специфичное для класса строки, игнорируется.Обычно (когда не имеет дело со строками),
Equals
сравнивает значения , а==
сравнивает ссылки на объекты . Если два объекта, которые вы сравниваете, ссылаются на один и тот же точный экземпляр объекта, то оба будут возвращать true, но если один имеет одинаковое содержимое и поступил из другого источника (это отдельный экземпляр с одинаковыми данными), только Equals будет верните истину. Однако, как отмечено в комментариях, строка - это особый случай, поскольку она переопределяет==
оператор, поэтому при работе исключительно со ссылками на строки (а не ссылками на объекты) сравниваются только значения, даже если они являются отдельными экземплярами. Следующий код иллюстрирует тонкие различия в поведении:Выход:
источник
==
и.Equals
оба зависят от поведения, определенного в фактическом типе, и фактического типа на сайте вызова. Оба являются просто методами / операторами, которые могут быть переопределены для любого типа и любого поведения, которого пожелает автор. По своему опыту я нахожу, что люди часто внедряют.Equals
в объект, но пренебрегают реализацией оператора==
. Это означает, что.Equals
будет фактически измерять равенство значений, в то время как==
будет измерять, являются ли они одной и той же ссылкой.Когда я работаю с новым типом, определение которого находится в потоке или пишу универсальные алгоритмы, я считаю, что лучшая практика заключается в следующем
Object.ReferenceEquals
напрямую (не требуется в общем случае)EqualityComparer<T>.Default
В некоторых случаях, когда я чувствую, что использование
==
неоднозначно, я буду явно использоватьObject.Reference
в коде equals для устранения неоднозначности.Эрик Липперт недавно сделал сообщение в блоге на тему, почему в CLR есть 2 метода равенства. Стоит прочитать
источник
== Оператор
.equals
источник
==
Оператор может быть перегружен для любого типа, а не только строки. Описание исключения в особом случае только для строки искажает семантику оператора. Было бы более точным, хотя, возможно, и не очень полезным, сказать: «если операнды являются ссылочными типами, он возвращает истину, если операнды ссылаются на один и тот же объект, если нет соответствующей перегрузки, и в этом случае реализация этой перегрузки определяет результат ». То же самое относится и кEquals
дополнительному усложнению, заключающемуся в том, что это виртуальный метод, поэтому его поведение может быть переопределено или перегружено.Во - первых, это разница. Для номеров
И для строк
В обоих случаях
==
ведет себя более полезно, чем.Equals
источник
==
оператора. Например, должно ли 16777216.0f быть равно (int) 16777217, (double) 16777217.0, обоим или ни одному? Сравнения между целочисленными типами хороши, но сравнения с плавающей точкой должны выполняться только IMHO со значениями, которые явно приводятся к совпадающим типам. Сравнение afloat
с чем-то, отличным от afloat
, или adouble
с чем-то, отличным от adouble
, кажется мне основным запахом кода, который не должен компилироваться без диагностики.x == y
не подразумеваетx/3 == y/3
(попробуйтеx = 5
иy = 5.0
)./
целочисленного деления дефектом в дизайне C # и Java. Паскальdiv
и даже VB.NET` are much better. The problems with
== `хуже, хотя:x==y
иy==z
это не значитx==z
(рассмотрим три числа в моем предыдущем комментарии). Что касается отношения, которое вы предлагаете, даже еслиx
иy
оба,float
или обаdouble
,x.equals((Object)y)
не подразумевают, что1.0f/x ==
1.0f / y` (если бы у меня были мои барабанщики, это гарантировало бы это; даже если==
не различать положительное и ноль,Equals
следует)Насколько я понимаю, ответ прост:
==
сравнивает ссылки на объекты..Equals
сравнивает содержимое объекта.String
Типы данных всегда действуют как сравнение содержимого.Надеюсь я прав и что он ответил на ваш вопрос.
источник
Я бы добавил, что если вы приведете ваш объект к строке, то он будет работать правильно. Вот почему компилятор выдаст вам предупреждение:
источник
object expr = XXX; if (expr == "Energy") { ... }
, то, поскольку левая часть имеет тип времени компиляцииobject
, компилятор должен использовать перегрузкуoperator ==(object, object)
. Проверяет равенство ссылок. Даст ли этоtrue
илиfalse
может быть трудно предсказать из-за интернирования строк . Если вы знаете, что левая сторона имеетnull
тип или типstring
,string
перед использованием используйте левую сторону==
.Поскольку статическая версия
.Equal
метода до сих пор не упоминалась, я хотел бы добавить это здесь, чтобы подвести итог и сравнить 3 варианта.где
MyString
переменная, которая приходит откуда-то еще в коде.Справочная информация и подвести итог:
В Java использование
==
для сравнения строк не должно использоваться. Я упоминаю об этом в случае, если вам нужно использовать оба языка, а также дать вам знать, что использование==
также может быть заменено на что-то лучшее в C #.В C # нет практической разницы для сравнения строк с использованием метода 1 или метода 2, если оба имеют тип string. Однако, если один имеет значение null, другой имеет другой тип (например, целое число) или один представляет объект, имеющий другую ссылку, то, как показывает первоначальный вопрос, вы можете столкнуться с тем, что сравнение содержимого на равенство может не дать того, что вы ожидаете.
Предлагаемое решение:
Поскольку использование
==
- это не то же самое, что использование.Equals
при сравнении, вы можете вместо этого использовать статический метод String.Equals . Таким образом, если две стороны не одного типа, вы все равно будете сравнивать содержимое, а если одна будет нулевой, вы избежите исключения.Это немного больше, чтобы написать, но на мой взгляд, безопаснее в использовании.
Вот некоторая информация, скопированная из Microsoft:
параметры
a
строкаПервая строка для сравнения или
null
.b
строкаВторая строка для сравнения или
null
.Возвращает
Boolean
true
если значениеa
совпадает со значениемb
; в противном случаеfalse
. Если обаa
иb
естьnull
, метод возвращаетtrue
.источник
Просто как дополнение к и без того хорошим ответам: это поведение не ограничивается строками или сравнением различных числовых типов. Даже если оба элемента имеют тип объекта одного и того же базового типа. "==" не сработает.
На следующем снимке экрана показаны результаты сравнения двух значений объекта {int}.
источник
Я немного смущен здесь. Если тип времени выполнения Content имеет тип string, то оба == и Equals должны возвращать true. Однако, поскольку это не так, то тип контента во время выполнения не является строкой, и вызов Equals для него делает ссылочное равенство, и это объясняет, почему Equals («энергетическая атака») завершается неудачно. Однако во втором случае решение о том, какой перегруженный == статический оператор должен быть вызван, принимается во время компиляции, и это решение выглядит как == (строка, строка). это говорит мне о том, что Content обеспечивает неявное преобразование в строку.
источник
Есть еще одно измерение в более раннем ответе @BlueMonkMN. Дополнительное измерение заключается в том, что ответ на заглавный вопрос @ Drahcir в том виде, в котором он указан, также зависит от того, как мы достигли
string
значения. Проиллюстрировать:Выход:
источник
Добавив еще один пункт к ответу.
.EqualsTo()
метод дает вам возможность сравнить с культурой и чувствительностью к регистру.источник
==
Маркер в C # используется для двух разных операторов равенства-проверки. Когда компилятор обнаруживает этот токен, он проверяет, реализован ли в одном из сравниваемых типов перегрузка оператора равенства для сравниваемых типов конкретных комбинаций (*) или для комбинации типов, в которую можно преобразовать оба типа. Если компилятор обнаружит такую перегрузку, он будет использовать ее. В противном случае, если оба типа являются ссылочными типами и не являются несвязанными классами (могут быть интерфейсом или связанными классами), компилятор будет рассматривать их==
как оператор сравнения ссылок. Если ни одно из условий не применимо, компиляция не удастся.Обратите внимание, что некоторые другие языки используют отдельные токены для двух операторов проверки равенства. Например, в VB.NET
=
токен используется в выражениях исключительно для перегружаемого оператора проверки равенства иIs
используется в качестве оператора reference-test или null-test. Использовать=
для типа, который не переопределяет оператор проверки на равенство, не удастся, так же как и для попытки использовать егоIs
для любой цели, кроме проверки ссылочного равенства или недействительности.(*) Типы обычно только перегружают равенство для сравнения с самим собой, но может быть полезно, чтобы типы перегружали оператор равенства для сравнения с другими конкретными типами; например,
int
мог бы (и ИМХО должен был, но не сделал) определить операторы равенства для сравнения сfloat
таким образом, чтобы 16777217 не сообщал о себе равным 16777216f. Как таковой, так как такой оператор не определен, C # будет повышатьint
tofloat
, округляя его до 16777216f до того, как оператор проверки равенства увидит его; Затем этот оператор видит два одинаковых числа с плавающей точкой и сообщает о них как о равных, не подозревая о том, что имело место округление.источник
3
как равный3.0f
. Если мы требуем, чтобы программист говорил, что предназначено в каждом случае, тогда нет опасности поведения по умолчанию, которое приведет к непредвиденным результатам, так как поведение по умолчанию отсутствует.Действительно отличные ответы и примеры!
Я просто хотел бы добавить фундаментальную разницу между ними,
Имея это в виду, если вы разработаете какой-либо пример (взглянув на левый и правый ссылочный тип и проверив / узнав, действительно ли в типе перегружен оператор == и равно ли он переопределен), вы наверняка получите правильный ответ. ,
источник
Когда мы создаем какой-либо объект, объект состоит из двух частей, одна из которых является контентом, а другая - ссылкой на этот контент.
==
сравнивает как содержание, так и ссылку;equals()
сравнивает только контентhttp://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq
источник
a
иb
обе являются строковыми ссылками, то результатa == b
не зависит от того, указывают ли ссылки на один и тот же объект.==
Оператор == может использоваться для сравнения двух переменных любого типа, и он просто сравнивает биты .
Примечание: в левой части int больше нулей, но нас это не волнует.
int a (00000011) == байт b (00000011)
Помните, что оператор == заботится только о структуре битов в переменной.
Используйте == Если две ссылки (примитивы) ссылаются на один и тот же объект в куче.
Правила одинаковы, независимо от того, является ли переменная ссылочной или примитивной.
a == c верно a == b неверно
битовые комбинации одинаковы для a и c, поэтому они равны при использовании ==.
Равно ():
Используйте метод equals (), чтобы увидеть , равны ли два разных объекта .
Например, два разных объекта String, которые оба представляют символы в «Джейн»
источник
object a = 3; object b = 3; Console.WriteLine(a == b);
. Вывод ложен, хотя битовые комбинации значений одинаковы. Типы операндов также имеют значение. Причина, по которой мы «не заботимся» о различном количестве нулей в вашем примере, заключается в том, что к тому моменту, когда мы вызываем оператор равенства, число нулей фактически одинаково из-за неявного преобразования.Единственная разница между Equal и == заключается в сравнении типов объектов. в других случаях, таких как ссылочные типы и типы значений, они почти одинаковы (либо оба имеют битовое равенство, либо оба являются ссылочным равенством).
объект: равно: побитовое равенство ==: ссылочное равенство
строка: (равно и == одинаковы для строки, но если одна из строк изменена на объект, результат сравнения будет другим) Равно: побитовое равенство ==: побитовое равенство
Смотрите здесь для более подробного объяснения.
источник