Почему object.Equals и instanceobject.Equals не совпадают

        string s1 = "t";
        string s2 = 't'.ToString();        

        Console.WriteLine(s1.Equals(s2)); // returning true
        Console.WriteLine(object.Equals(s1, s2)); // returning true

Здесь он возвращает тот же результат. Теперь, когда я использую StringBuilder, он не возвращает то же значение. Что скрывается под причиной?

        StringBuilder s1 = new StringBuilder();
        StringBuilder s2 = new StringBuilder();

        Console.WriteLine(s1.Equals(s2)); // returning true
        Console.WriteLine(object.Equals(s1, s2)); // returning false

Edit1: ответ на мой вышеупомянутый вопрос приведен ниже. Но во время этого обсуждения мы выяснили, что StringBuilder не имеет в своей реализации переопределяющего метода Equals. Поэтому, когда мы вызываем StringBuilder.Equals, он фактически переходит в Object.Equals. Поэтому, если кто-то вызовет StringBuilder.Equals и S1.Equals (S2), результат будет другим.


person Pritam Karmakar    schedule 19.03.2012    source источник
comment
Хороший улов! В итоге, StringBuilder, похоже, забыл переопределить Equals(object). Кажется нелогичным иметь Equals(StringBuilder) поведение, отличное от Equals(object).   -  person leppie    schedule 19.03.2012


Ответы (3)


String.Equals () переопределяется в C # таким образом, что идентичные строки фактически являются Equal(), когда используется Equal() переопределение, определенное в string.

Если вы сравниваете строковые литералы (не в вашем примере), стоит отметить, что идентичные строковые литералы интернированы .. . то есть идентичные строки живут по одному и тому же адресу, поэтому они также будут равны по ссылке (например, object.Equals () или s1.ReferenceEquals (s2)), а также по значению.

StringBuilder предоставляет перегрузку для Equals(), которая принимает StringBuilder в качестве параметра (то есть s1.Equals(s2) вызовет эту перегрузку вместо вызова object.Equals(object obj)).

http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.equals.aspx

StringBuilder.Equals () - это ...

Значение true, если этот экземпляр и sb имеют равные значения string, Capacity и MaxCapacity; в противном случае - ложь.

object.Equals () использует статический Equals (), определенный для объекта, который проверяет только равенство ссылок (если передан класс) или равенство значений (если передана структура).

Итак, в итоге

string s1 = "t";
string s2 = 't'.ToString();        

Console.WriteLine(s1.Equals(s2)); // true because both reference equality (interned strings) and value equality (string overrides Equals())
Console.WriteLine(object.Equals(s1, s2)); // true because of reference equality (interned strings)

StringBuilder s1 = new StringBuilder();
StringBuilder s2 = new StringBuilder();

Console.WriteLine(s1.Equals(s2)); // true because StringBuilder.Equals() overloaded
Console.WriteLine(object.Equals(s1, s2)); // false because the two StringBuilder instances have different addresses (references not equal)
person Eric J.    schedule 19.03.2012
comment
Технически StringBuilder только перегружает метод Equals без переопределения виртуального объекта. Это причина того, что два метода ведут себя по-разному. Интересно, забыли ли они сделать это в NET1.0 и не хотели вносить критические изменения? - person alexm; 19.03.2012
comment
@alexm: Хороший улов. Раньше я этого не замечал. Обновил свой ответ. - person Eric J.; 19.03.2012
comment
Спасибо Эрику за красивое объяснение. Если я сделаю небольшое резюме из этого: object.Equals будет проверять ссылку или значение в зависимости от типа входного объекта. В то время как String и StringBuilder имеют свой собственный метод перегрузки / переопределения Equal, который будет работать в соответствии с их реализацией. Пожалуйста, поправьте меня, если я ошибаюсь. - person Pritam Karmakar; 19.03.2012
comment
Также я обновил 2 объявления конструкторов строк как - StringBuilder s1 = new StringBuilder (abc, 10); StringBuilder s2 = новый StringBuilder (abc, 10); Тогда почему менее двух экземпляров возвращают другое значение Console.WriteLine (s1.Equals (s2)); // правда Console.WriteLine (StringBuilder.Equals (s1, s2)); // false Заранее спасибо - person Pritam Karmakar; 19.03.2012
comment
Идентичные строки по умолчанию не интернируются; это легко доказать с помощью следующего кода: object.ReferenceEquals(new StringBuilder("abc").ToString(), new StringBuilder("abc").ToString()) (который возвращает false). Обратите внимание, что идентичные строковые литералы в программе на C # будут ссылаться на один и тот же объект. Когда два или более строковых литерала, эквивалентных в соответствии с оператором равенства строк (раздел 7.9.7), появляются в одной сборке, эти строковые литералы относятся к одному и тому же экземпляру строки. (msdn.microsoft.com/en-us/library/aa691090.aspx) - person Bradley Grainger; 19.03.2012
comment
@Bradley: Думаю, вы не ответили на мой последний вопрос. В приведенном выше комментарии я прошу: согласно msdn (msdn.microsoft.com /en-us/library/ccth01t4.aspx) для метода построителя строк Equals true, если этот экземпляр и sb имеют равные значения string, Capacity и MaxCapacity; в противном случае - ложь. Чтобы проверить это, я создал 2 объекта sb с одинаковым содержимым и одинаковой емкостью. Но когда я использую s1.Equals (s2) и StringBuilder.Equals (s1, s2), я получаю другой результат. Я хочу знать, почему это так. Спасибо за ответ. - person Pritam Karmakar; 19.03.2012
comment
@Bradley: Спасибо, что указали на это. Я исправил эту часть ответа. - person Eric J.; 19.03.2012
comment
static object.Equals должен просто вызывать экземпляр Equals. В ваших примерах кода неверно указано ссылочное равенство. Для этого вам понадобится object.ReferenceEquals. - person leppie; 19.03.2012
comment
@PritamKarmakar: Причина наблюдаемого поведения в том, что StringBuilder реализует Equals(StringBuilder), но не отменяет object.Equals(object) с той же семантикой. Я считаю это ошибкой. @alexm, вероятно, прав, предполагая, что это была ошибка в ранней версии Framework, и они не исправили ее для обратной совместимости. - person Bradley Grainger; 19.03.2012
comment
@BradleyGrainger: Спасибо. Да, похоже, это ошибка. Я просто проверяю реализацию StringBuilder и не вижу там переопределения метода Equal. - person Pritam Karmakar; 19.03.2012

Класс строк реализует Equals таким образом, что сравнивает значения строк.

Большинство экземпляров объектов, если они не реализуют другой тип сравнения, проверяют, совпадают ли ссылки на объект.

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

person competent_tech    schedule 19.03.2012

общий метод Equals сравнивает ссылки двух объектов, чтобы узнать, есть ли у них ссылка для ссылочных типов, таких как StringBuilder. Для типов значений, а string ведет себя как тип значения (неизменяемый), он выполняет побитовое сравнение (определяет, является ли двоичное представление таким же). Однако эта функция перегружена в классе StringBuilder.

Согласно MSDN, метод равенства StringBuilder вернет true, если следующие критерии для обоих объектов StringBuilder равны:

  • Нить
  • Емкость
  • MaxCapacity

Таким образом, s1 и s2 во втором примере не соответствуют ссылочному равенству, но передают настраиваемое равенство StringBuilder Equals на основе только что упомянутых критериев.

person Matt    schedule 19.03.2012
comment
Строка не является типом значения. (Это ссылочный тип с семантикой значений.) stackoverflow.com/questions/1069155/ - person Bradley Grainger; 19.03.2012
comment
@BradleyGrainger, я знал, что технически это не тип значения, но в данном случае он действует так же. Я обновлю свой ответ, чтобы уточнить. Спасибо. - person Matt; 19.03.2012