Вопрос о ссылках на строки в C # - PullRequest
2 голосов
/ 02 июля 2011

Быстрый вопрос.

Возьмите следующий пример кода:

ArrayList arrayList = new ArrayList();
string testString = "";
testString = "test";
arrayList.Add(testString);

В этом примере кода, если бы я сделал следующее:

arrayList[0] = "anotherTest";

Будет ли testString изменен на другой текст или он останется таким же? Это тот объект, который вставлен или его копия, другая строка?

Спасибо, Christian

Ответы [ 7 ]

4 голосов
/ 02 июля 2011

До:

Before

После того, как:

After

  • Только значение arrayList [0] изменяется на ссылку на "anotherTest". Значение переменной testString остается неизменным.

  • Строка является ссылочным типом. Это означает, что как переменная testString, так и arrayList [0] каждый (независимо) содержат ссылку на объекты "test" и "anotherTest", а не само значение.

  • Изменение testString или arrayList [0] из одной строки в другую не приводит к изменению исходной строки. Строки неизменны. Изменяется только ссылка на строковый объект.

2 голосов
/ 02 июля 2011

Когда вы завершили первый блок кода

 ArrayList arrayList = new ArrayList(); 
 string testString = "";
 testString = "test";
 arrayList.Add(testString);

у вас есть две ссылки: одна на arrayList и одна на testString.

Первый элемент в arrayList ссылается на тот же объект, что и testString, то есть строка со значением "test".

Arraylist содержит ссылку на объект testString, но элемент массива 0 и переменная testString обе ссылаются на один и тот же объект.

Когда вы делаете назначение

    `arrayList[0] = "anotherTest";`

вы неявно создаете экземпляр нового string объекта, содержащего "anotherTest". Этот объект хранится в элементе массива с индексом null.

Таким образом, после того, как элемент 0 массива второго блока ссылается на новый строковый объект, а testString продолжает ссылаться на исходную строку.

2 голосов
/ 02 июля 2011

Здесь есть 2 объекта: "test" и "anotherTest".

Этап 1:

arrayList.Add(testString) //Adds the reference stored in testString 
                          //to the end of arrayList.

После выполнения этой строки arrayList [0] также содержит ссылку на «test» (поскольку на этом этапе testString содержит ссылку на объект"test").

Вы можете проверить это:

Console.WriteLine(object.ReferenceEquals(testString, arrayList[0])); //outputs true

Этап 2:

arrayList[0] = "anotherTest"; //stores a reference to the object "anotherTest" in
                              //arrayList[0]

Мы не изменили testString вообще.Это все еще ссылки на «тест».Вы можете проверить, что ссылки, хранящиеся в arrayList [0] и testString, разные:

Console.WriteLine(object.ReferenceEquals(testString, arrayList[0])); //outputs false

testString -> хранит ссылку на «test»

1 голос
/ 02 июля 2011

В вашем примере вы сами обновляете первый индекс списка, а не исходную строку, которая была добавлена ​​в список.

, даже если вы не используете строку, например, класс Bitmap или даже int struct:

int i = 14;

List<int> myList = new List<int>();
myList.Add(i);

myList[0] = 3;

это не повлияет на оригинал i и останется 14.

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

string s1 = "some text";
string s2 = s1;
s2 += " another text";

s1 останется без изменений.

Обычный класс не будет неизменным, например:

class MyClass
{
    public string MyString;
}

MyClass class1 = new MyClass();
class1.MyString = "Some String";
MyClas class2 = class1;
class2.MyString = "Other String";

Это повлияет на строку class1, как и теперь, теперь это "Другая строка", и это потому, что классы являются ссылочными типами.

0 голосов
/ 02 июля 2011

На самом деле ни один из трех ответов пока не очень точен.

Переменная testString всегда содержит ссылку на «test» в примере. Это никогда не меняется.

Что более важно, ArrayList также является контейнером, который содержит ссылки на объекты. Поэтому, когда вы присваиваете «anotherTest» 0-му элементу, вы фактически делаете 0-й элемент ссылкой на другой строковый объект. Это не меняет значение testString.

0 голосов
/ 02 июля 2011

Ну, вы всегда можете запустить код, чтобы узнать;).

Ответ таков: testString не изменится. Ответ @ dtb объясняет почему. Я подойду к другому аспекту проблемы, касающемуся вашего: «Это тот объект, который вставлен или его копия, другая строка?» вопрос.

Давайте разберем, что происходит в вашем коде:

  • testString содержит ссылку на "test".
  • Вызов arrayList.add(testString) устанавливает arrayList[0] как ссылку на "test".
  • Doing arrayList[0] = "anotherTest" устанавливает arrayList[0] как ссылку на "anotherTest".

Итак, как вы видите, копирование никогда не происходит. Строки не копируются или (как это было сказано в некоторых других ответах) «передаются по значению».


Если бы ваш вопрос касался типа значения , например struct или даже просто int, то ответ все же будет таким, что testInt не изменится, но в в этом случае причина заключается в том, что произошло копирование: типы значений «передаются по значению», и их копии создаются при использовании оператора =.

0 голосов
/ 02 июля 2011

Короткий ответ на ваш вопрос "нет".

Почему? Поскольку строки являются неизменяемыми.

И вот почему:

Из Википедии:

Если объект, как известно, является неизменным, он может бытьскопировать просто сделав копию ссылки на него вместо копирования всего объекта.- Wikipedia.org

Давайте рассмотрим пример:

var a = "Testing";
var b = a;

Здесь у вас уже есть строка («Тестирование») вкакое-то место в памяти (скажем, местоположение 0x001. Таким образом, фактическое значение «a» становится 0x001 в первой строке.

И мы устанавливаем b = a во второй строке ... так что b также устанавливаетсяв 0x001 (так как мы копируем ссылки ).

Теперь предположим, что мы делаем это:

a = "Again";

Здесь у нас есть другая строка («Опять»)сидя в каком-то другом месте в памяти (скажем, в месте 0x022).

Мы знаем, что строки неизменны ... так что здесь происходит? Ну ... это означает, что мы назначаем по ссылке. Итак, значение "a "становится 0x022.

Что это значит для" b "?

Это означает, что любые переменные, указывающие на 0x001 (" Тестирование "), ПО-прежнему будут указывать на 0x001 ... так что, вв этом случае «b» остается неизменным.

И только «a», который мы обновили, изменив ссылку , будет указывать на 0x022.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...