Почему сравнение двух строк как объекта приводит к неожиданному результату
Рассмотрим следующий фрагмент кода.
object str = new string(new char[] { 't', 'e', 's', 't' });
object str1 = new string(new char[] { 't', 'e', 's', 't' });
Console.WriteLine(str==str1); // false
Console.WriteLine(str.Equals(str1)); // true
Я понимаю, что оператор равенства работает здесь, так как мы неявно приводим объект, оператор равенства проверяет ссылки обоих, если они равны, и возвращает false.
Но я запутался во втором, возвращая true, похоже, что он вызывает реализацию переопределения Equals, предоставляемую типом String, и он проверяет содержимое строки, если они равны.
Мой вопрос заключается в том, почему он также не проверяет равенство содержимого для оператора, их фактический тип - строка, а не объект. право?
в то время как следующий код выводит ture для обоих:
object str = "test";
object str1 = "test";
Console.WriteLine(str==str1); // true
Console.WriteLine(str.Equals(str1)); // true
5 ответов
С:
Console.WriteLine(str==str1); // false
во время компиляции определяется, какая предустановленная (формальная) перегрузка C# operator ==
использовать. поскольку str
а также str1
объявлены как object
Перегрузка operator ==(object, object)
выбран. Это исправлено во время компиляции. То, что фактические типы времени выполнения более специфичны, не меняется. Если вы хотите связать во время выполнения, используйте Console.WriteLine((dynamic)str == (dynamic)str1); /* true */
вместо.
С:
Console.WriteLine(str.Equals(str1)); // true
Вы вызываете виртуальный метод на object
, Виртуальный означает, что он пойдет на что угодно override
актуально во время выполнения. Класс System.String
имеет переопределение, и с str
будет иметь тип времени выполнения System.String
переопределение будет использоваться "виртуальной отправкой".
Что касается дополнения в нижней части вашего вопроса: эта ситуация отличается из-за интернирования строк. Строковое интернирование - это оптимизация, при которой один и тот же физический экземпляр используется для формально различных строк, значения которых идентичны. Когда у вас есть две строки, значения которых приведены в исходном коде, интернирование строк "оптимизирует" и сделает две ссылки на один и тот же экземпляр. Это обычно безвредно, потому что строки гарантированно будут неизменными. Поэтому обычно вам все равно, если это тот же экземпляр или другой экземпляр с одинаковым значением. Но в вашем примере мы можем "раскрыть" стажировку.
Примечание: интернирование строк не относится к вашему первоначальному вопросу. Только после того, как вы добавили новый пример в свой вопрос, интернирование строк стало актуальным.
Когда == используется в выражении объекта типа, оно преобразуется в System.Object.ReferenceEquals.
Equals - это просто виртуальный метод, который ведет себя как таковой, поэтому будет использоваться переопределенная версия (которая для строкового типа сравнивает содержимое).
Это происходит из-за интернирования строк; когда ты пишешь:
object str = "test";
object str1 = "test";
Console.WriteLine(str==str1);
Это работает, как и ожидалось, поскольку две строки внутренне и незаметно копируются компилятором в одно место, поэтому два указателя фактически указывают на один и тот же объект.
Если вы создаете строку из массива символов, компилятор не достаточно умен, чтобы понять ваше намерение, и это эквивалентно приведенному выше, поэтому, будучи строкой ссылочного типа, они фактически являются двумя различными объектами в памяти.
Посмотрите эту статью: https://blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/
Метод Equals переопределен в строке, поэтому он сравнивает фактическое содержимое строки, а не адрес, как == (ReferenceEquals) в вашем случае, поскольку тип является объектом.
Я считаю, что это потому, что String
==
оператор только берет string
типы в качестве параметров, в то время как .Equals
метод занимает object
типы в качестве параметров.
Поскольку строка ==
только взять string
Типы в качестве параметров, разрешение перегрузки выбирает объект ==
оператор использовать для сравнения.
Помощь String.Equals
Метод дает это в качестве замечания:
Этот метод выполняет порядковое (с учетом регистра и без учета культуры) сравнение.
Таким образом, сравнение выполняется путем проверки строки char по char, что дает значение true.