Ссылки на строки в C#
Ссылка переменной строки совпадает со ссылкой той же переменной, приведенной к object. Но две ссылки одинаковых строк, приведенных к object, не совпадают. Почему так происходит если строки immutable? У констант в том же кейсе ссылки совпадают, но не совпадают с введенными строками.
Код приложения:
class Program
{
const string S1 = "123";
const string S2 = "123";
static void Main(string[] args)
{
var s1 = Console.ReadLine(); // 123
var s2 = Console.ReadLine(); // 123
Console.WriteLine(s1 == s2); // True
Console.WriteLine(s1 == (object)s1); // True
Console.WriteLine(s2 == (object)s2); // True
Console.WriteLine(s1 == (object)s2); // False
Console.WriteLine((object)s1 == (object)s2); // False
Console.WriteLine((object)S1 == (object)S2); // True
}
}
Ответы (2 шт):
Но две ссылки одинаковых строк, приведенных к object, не совпадают.
Потому что операторы не виртуальны, а определяются на этапе компиляции на основание типов. Если вы сделали преобразование в object то будет вызван оператор ==, который просто сравнит ссылки, а они не равны вот и False.
class Program
{
const string S1 = "123";
const string S2 = "123";
static void Main(string[] args)
{
var s1 = Console.ReadLine(); // 123
var s2 = Console.ReadLine(); // 123
// вызывается оператор сравнения строк
Console.WriteLine(s1 == s2); // True
// вызывается оператор сравнения объекта,
// т.к. это один и тож же то ссылки равны
Console.WriteLine(s1 == (object)s1); // True
Console.WriteLine(s2 == (object)s2); // True
// вызывается оператор сравнения объекта,
// т.к. это разные объекты то false
Console.WriteLine(s1 == (object)s2); // False
Console.WriteLine((object)s1 == (object)s2); // False
// тут тоже сравнение объектов, но оно равно,
// т.к. это оптимизация компилятора и рантайма,
// происходит интернирование строк и создается только
// один объект в памяти
Console.WriteLine((object)S1 == (object)S2); // True
}
}
Также можно посмотреть скомпилированный код: SharpLab
Где будет видно какой оператор сравнения вызывается.
В C# существует интернирование строк, это способ хранения только одной копии строк, чтобы под одинаковые строки память не выделялась из раза в раз. Вы можете изменить свой код на следующий
static void Main(string[] args)
{
var first = "1";
var second = string.Intern(Console.ReadLine());
Console.WriteLine(object.ReferenceEquals(first, second));
}
и тогда при вводе значения строки уже хранящейся в пуле будет возвращена ссылка на уже имеющуюся строку, если же в пуле нет такой строки, то эта строка будет добавлена и будет возвращена ссылка на неё.