Подтвердить что ты не робот

Попытка понять == оператор с объектами

object a = "1";
object b = "1";
Console.WriteLine(a == b); // returns True

object c = 1;
object d = 1;
Console.WriteLine(c == d); // returns False

Приведенный выше код возвращает разные результаты для integer и string. Я не мог понять, почему. Может кто-то, пожалуйста, помогите мне понять причину этого?

И в чем разница между == (operator) и ReferenceEquals (function)?

4b9b3361

Ответ 1

Хотя Ed S ответил, что == проверяет ссылочное равенство. Просто добавьте MSDN, которая также говорит то же самое

Для предопределенных типов значений оператор равенства (==) возвращает true, если значения его операндов равны, в противном случае - false. Для справки типы, отличные от string, == возвращает true, если его два операнда ссылаются на тот же объект. Для типа строки == сравнивает значения строки.

Если вы хотите сравнить объекты, вы можете использовать метод Equals.

Также, как вы задали разницу между == и referenceEquals, вы должны заметить, что == перегружает и Equals переопределяет.

Итак, если вы скажете, что

string x = "ABCD";
string y = 'A' + "BCD"; // ensure it a different reference

if (x == y) { // evaluates to TRUE

так как метод, который будет использоваться для сравнения переменных x и y, определяется в время компиляции. Строки неизменяемы, поэтому нет вреда при использовании == перегруженного для поддержки равенства значений для строк. Когда компилятор оптимизирует строковые литералы, он видит, что оба x и y имеют одинаковое значение и, следовательно, вам нужен только один строковый объект. Это безопасно, потому что String неизменна в С#.

Если вы используете Equals, то тип переменной определяется в время выполнения на основе фактического типа внутри переменной x.

object x = "ABCD";
object y = 'A' + "BCD"; // ensure it a different reference

if (x == y) { // evaluates to FALSE

тогда

object x = "ABCD";
object y = 'A' + "BCD"; // ensure it a different reference

if (x.Equals(y)) { // evaluates to TRUE

Также вы можете проверить Рекомендации по переопределению равных() и операторов == (Руководство по программированию на С#)

В С# существует два разных типа равенства: ссылочное равенство (также известный как идентификатор) и равенство значений. Ценностное равенство обычно понимаемое значение равенства: это означает, что два объекта содержат те же значения. Например, два целых числа со значением 2 имеют значение равенства. Исходное равенство означает, что не существует двух объекты для сравнения. Вместо этого существуют две ссылки на объекты и из них относятся к одному и тому же объекту.

[...]

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

Ответ 2

Объявление целых чисел как object приводит к операции в боксе. Теперь, когда они помещены в поле, оператор равенства выполняет сравнительное сравнение, а ссылки не совпадают. Тип string, однако, определил свой собственный оператор равенства и выполняет сравнение значений (т.е. "Являются ли мои символы такими же, как и другие строковые символы?" )

EDIT: Per @Enigmativity, я упустил тот факт, что две строки были объявлены как object. Это усложняет ситуацию. Мой предыдущий оператор о строках здесь неверен, потому что operator== не является полиморфным. Сравнение возвращает true, потому что эти строки интернированы, то есть они фактически являются одним и тем же объектом, поэтому ссылочное сравнение возвращает true.

Ответ 3

Этот код возвращает false:

object a = "a";
object b = a + "b";
a = "ab";
Console.WriteLine(a == b); // returns False

Этот код возвращает true:

object a = "ab";
object b = "ab";
Console.WriteLine(a == b); // returns True

Но в обоих случаях значение в a и b равно "ab". Разница в том, что для второго набора кода компилятор оптимизирует код и использует ту же строку.

Итак, строки как объекты оценивают == как ссылочные равны. Нет никакой разницы.

Ответ 4

Ток == в С# используется для представления двух операторов: перегружаемого оператора равенства и неперегружаемого оператора эталонной эквивалентности. В случаях, когда для обоих операндов определена перегрузка равенства, она будет использовать прежний оператор; в противном случае он попытается использовать последний. Поскольку Object не определяет никаких перегрузок с проверкой равенства, С# интерпретирует токен == как ссылающийся на второй оператор ссылочной эквивалентности.

Причина, по которой строки в ваших примерах сравниваются равны, заключается не в том, что сгенерированный код исследует их контент, а скорее связан с тем, как строковые литералы реализованы. Когда сборка компилируется, компилятор строит список всех строковых литералов, которые появились внутри него; длины и содержимое всех строк в этом списке включаются как кадр в сгенерированной сборке. В каждом месте в коде используется строковый литерал, компилятор вводит команду "загружать ссылку на * n * -й строку", а после генерации всего кода компилятор включает в сборку последовательности символов каждого строкового литерала содержащиеся в нем. Когда сборка загружается,.NET Runtime создаст таблицу ссылок String, сгенерирует экземпляры String для всех последовательностей символов, определенных в этой сборке, и сохранит ссылки на вновь созданные строки в таблице. Как следствие всего этого, установка переменной в строковый литерал "Джордж" не создает новый строковый объект, а скорее заставляет переменную идентифицировать объект, который содержит шестисимвольную последовательность Джорджа, которая была создана при первом загрузке кода.

Если компилятор и/или среда выполнения обнаруживают, что одна и та же последовательность символов отображается в нескольких строковых литералах, запросы на последующие литералы, содержащие эту последовательность, могут быть удовлетворены ссылкой на объект String, который был создан для более ранний. В общем случае код должен быть написан таким образом, чтобы не заботиться о том, когда такая замена происходит. В случаях, когда литерал появляется несколько раз в исходном файле, компилятор почти наверняка заменит все вхождения ссылками на один и тот же экземпляр строки, но хорошо написанный код не должен полагаться на это.

В вашем примере все соответствующие использования литерала "1" отображаются в одном файле и поэтому заменяются ссылками на один и тот же строковый объект, но вполне возможно, что другие экземпляры String, которые содержат один символ 1 может существовать; используя оператор == для сравнения строкового литерала "1" с переменной типа Object, которая идентифицирует одну из этих других строк, даст false.

Ответ 5

Определение выглядит так: Из String.cs

public static bool operator == (String a, String b) {
       return String.Equals(a, b);

И определение равного метода:

public static bool Equals(String a, String b) {
            if ((Object)a==(Object)b) {
                return true;
            }

            if ((Object)a==null || (Object)b==null) {
                return false;
            }

            if (a.Length != b.Length)
                return false;

            return EqualsHelper(a, b);
        }