Вопрос о c # и string вне класса или функции против string внутри класса или функции

#c#

#c#

Вопрос:

Я знаю, что string является ссылочным типом, но у меня возникают проблемы с пониманием того, почему string вне класса или функции «refTest» не будет вести себя так, как внутри класса «refTest». Я имею в виду, если у меня есть 2 строки с именами «name» и «name2», и обе имеют одинаковое значение, поскольку name2 имеет копию name, оно будет выводить одно и то же значение «A», но затем я меняю второе строковое значение на «B», и на этот раз name и name2 имеют разные значениязначение «A» и «B», а затем, когда я проделаю то же самое со строкой из класса «refTest», она выведет name1 и name2 с одинаковым значением. Разве оба типа string не являются ссылочными? Это означает, что у них есть указатель на кучу. Верно? Я запутался в том, почему строка вне класса «refTest» выдаст другой результат по сравнению с тем, который находится внутри класса «refTest».

Или дело в том, что каждый раз, когда я объявляю строку вне класса «refTest», она будет храниться на другом адресе (адрес кучи)?

 class Program
{
    static void Main(string[] args)
    {
        
        string name = "A";
        string name2 = name;
        Console.WriteLine(name2   " "   name);
        // >> A A
        name2 = "B";
        Console.WriteLine(name2   " "   name);
        // >> A B


        refTest test = new refTest();
        test.rTName = "A";
        Console.WriteLine(test.rName);
        // >> A
        refTest test2 = test;
        test2.rName = "B";
        Console.WriteLine($"test.rName = {test.rName}, test2.rName = {test2.rName}");
        // >> test.rName = B, test2.rName = B
        Console.ReadLine();
    }

}


class refTest
{
    public string rName;
}
 

Комментарии:

1. test и test2 это одно и то же; чего вы ожидаете, чтобы быть другим? (ps; Я так понимаю, это test.rTName опечатка?)

2. Строки в C # сильно отличаются от строк в Java или массивов символов в C. Ответ Магнетрона объясняет, как работают строки в C #.

Ответ №1:

string , хотя и является ссылочным типом, он является неизменяемым. Это означает, что когда вы это делаете name2 = "B" , вы создаете новый экземпляр и name2 указываете на новый экземпляр, в то name же время указывая на старый.

Теперь для вашего пользовательского класса, когда refTest test2 = test; вы это делаете test2 , вы указываете на тот же объект, test что и , и когда вы изменяете свойство или поле в одном из них, поскольку они оба указывают на один и тот же объект, оба test и test2 будут отображать новое значение.

Комментарии:

1. Теперь все ясно. Спасибо. Итак, каждый раз, когда я объявляю строку в основной функции, это означает, что я «создаю» новый адрес (кучу)? И я знаю эту кучу .

2. это не объявление, которое создает новый экземпляр, это присвоение @twinspectre .. System.String является ссылочным типом. он будет null иметь размер 0 байт до тех пор, пока ему не будет присвоен (или создан экземпляр).

3. итак, если у меня есть строка с именем Characters (я знаю, что для отдельных символов есть символ char), и я присваиваю = «A», и я использую ту же переменную, и я присваиваю «B», означает ли это, что A будет «сохранен» по своему исходному адресу, а B (та же переменная, что и раньше) будут ли они «сохранены» на другом адресе?

4. Я не знаю, сохранятся ли эти ссылки, но вот скриншот кучи неустановленной строки pasteboard.co/JJl2RhX.png обратите внимание, что args — это массив строк. и через пару шагов он создается. pasteboard.co/JJl6h64.png

5. Я скажу, что, хотя я ожидал увидеть string name2 = name be created в куче как новый экземпляр (хотя в моем ss это было testString2 = testString1 ), этого не было .. по крайней мере, не в области Main . Хотя, возможно, в области Encoder, поскольку сравнение этих снимков действительно представляло увеличение размера.

Ответ №2:

Вот что происходит в памяти по мере выполнения вашего кода (только назначения). На самом деле речь идет не о неизменности строки, а о том, что указывает на что:

введите описание изображения здесь

Никогда не бывает так, чтобы приравнивание одной переменной к другой устанавливало цепочку

 string x = "hello";

string y = x;
 

Оба y и x указывают на «привет». Это не тот случай, когда «y указывает на x, а затем x указывает на hello, и если вы измените, на что указывает x, y это увидит»

 YES:   y --> hello <-- x
NO:    y --> x --> hello
 

Но у вас есть цепочка, когда какая-то переменная указывает на класс, и у этого класса есть переменная, которая указывает на что-то еще. Это то, что у вас было с вашим refTest ; ваш test и test2 указывает на экземпляр reftest , который указывает на имя A , а позже вы заменили имя.. Это устанавливает цепочку ссылок, в которой замена некоторой части цепочки означает, что что-то вышестоящее видит это

Комментарии:

1. Каждый раз, когда я объявляю переменную, это означает, что в куче «создается» новый адрес.

2. Я собираюсь сказать «нет», но не совсем понятно, что вы имеете в виду. Читайте о том, как стек и куча используются в C #. Избегайте попадания в ловушки чрезмерно упрощенных эмпирических правил, таких как «типы значений находятся в стеке, а ссылочные типы — в куче». Ваш вопрос на самом деле не имеет никакого отношения к стеку и куче