Поведение String.Equals и ==
Вчера, когда я отправлял ответ на вопрос здесь, я столкнулся с проблемой, как String.Equals
и ==
ведут себя разные в разных ситуациях.
Мне нужен вывод поведения String.Equals
и ==
.
bool result = false;
object obj = "String";
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;
// obj, str2, str4 references are same.
// obj is object type and others are string type
// Comparision between object obj and string str2 -- Com 1
result = String.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true
// Comparision between object obj and string str3 -- Com 2
result = String.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false
// Comparision between object obj and string str4 -- Com 3
result = String.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true
// Comparision between string str2 and string str3 -- Com 4
result = String.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true
// Comparision between string str2 and string str4 -- Com 5
result = String.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true
// Comparision between string str3 and string str4 -- Com 6
result = String.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true
// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false
Я смотрю также на часы
obj "String" {1#} object {string}
str2 "String" {1#} string
str3 "String" {6#} string
str4 "String" {1#} string
obj2 "String" {6#} object {string}
и прочитайте статьи здесь и здесь
Почему Com1, Com2, Com3, Com4, Com5 и Com6 имеют разные типы поведения?
Ответы
Ответ 1
Оператор ==
имеет различное поведение для strings
и всех других типов ссылок. Если оба операнда ==
равны string
, то используется сравнение String.Equals
. В противном случае ==
эквивалентно Object.ReferenceEquals
Из С# == Документация оператора:
Для предопределенных типов значений оператор равенства (==) возвращает true, если значения его операндов равны, в противном случае - false. Для справки типы, отличные от string, == возвращает true, если его два операнда ссылаются на тот же объект. Для типа строки == сравнивает значения строки.
Другим эффектом, который вы видите, является string intering. В вашем коде есть только одна ссылка на литеральное значение "String"
. Вы код эквивалентен: obj = str2 = str4 = "String"
. obj, str2 и str4 - все ссылки на одну и ту же базовую строку. Поскольку str3 генерируется во время выполнения, она устанавливается в другую строку, которая имеет такое же значение "String".
Подводя итог:
- com1: result = (obj == str2);//true
- сравнивает
object
и string
, поэтому выполняет проверку равенства ссылок
- obj и str2 указывают на одну и ту же ссылку, поэтому результат верен.
- result = (obj == str3);//false
- сравнивает
object
и string
, поэтому выполняет проверку равенства ссылок
- obj и str3 указывают на разные ссылки, поэтому результат ложный
- result = (obj == str4);//true
- сравнивает
object
и string
, поэтому выполняет проверку равенства ссылок
- obj и str4 указывают на одну и ту же ссылку, поэтому результат верен.
- result = (str2 == str3);//true
- сравнивает
string
и string
, поэтому выполняет проверку значения строки
- str2 и str3 являются "String", поэтому результат верен.
- result = (str2 == str4);//true
- сравнивает
string
и string
, поэтому выполняет проверку значения строки
- str2 и str4 являются "String", поэтому результат верен.
- result = (str3 == str4);//true
- сравнивает
string
и string
, поэтому выполняет проверку значения строки
- str3 и str4 являются "String", поэтому результат верен.
- result = (obj == obj2);//false
- сравнивает
object
и object
, поэтому выполняет контрольную проверку равенства
- obj и obj2 указывают на разные ссылки, поэтому результат ложный
Помните, что тип сравнения, который выполняет ==
, выбирается во время компиляции, поэтому он основан на статическом типе операндов. Компилятор не знает, что obj и obj2 всегда будут указывать на строки.
Ответ 2
Equals
сравнивает ссылки для типов ссылок и значений для типов значений. String
- это ссылочный тип, который ведет себя как тип значения. String
может хранить много данных, поэтому он должен храниться в куче, но он неизменен и ведет себя как любой другой тип значения.
Метод Equals
на String
сравнивает значение строки с другим объектом (который должен быть String
).
ReferenceEquals
определяет, являются ли два ссылочных типа одним и тем же экземпляром. Поскольку String
являются ссылочными типами, но неизменяемы, они интернируются, чтобы позволить одному и тому же строковому литералу ссылаться на разные строки.
Наконец, оператор равенства проверяет равенство между значениями String
s. В случае
typeof(string).Name == (object)"String"
результат возвратит false
, так как левый операнд на самом деле является константой, встроенной в определение типа строки, и не использует одну и ту же ссылку на строковый литерал, и поскольку правый операнд помещен в бокс, сравниваются их ссылки.