Ссылки на строки в 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 шт):

Автор решения: Exploding Kitten

Но две ссылки одинаковых строк, приведенных к 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

Где будет видно какой оператор сравнения вызывается.

→ Ссылка
Автор решения: motpfofs

В C# существует интернирование строк, это способ хранения только одной копии строк, чтобы под одинаковые строки память не выделялась из раза в раз. Вы можете изменить свой код на следующий

static void Main(string[] args)
{
    var first = "1";
    var second = string.Intern(Console.ReadLine());

    Console.WriteLine(object.ReferenceEquals(first, second));
}

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

Подробнее можно почитать тут и тут.

→ Ссылка