Хотя это не является основной проблемой, запутанным фактором является то, что строки являются неизменяемыми, что означает, что если вы «измените», то они будут выброшены, и будет создана новая. Я вернусь к этому моменту через мгновение
Основная проблема заключается в том, что вы не можете установить sh ссылку на что-то:
string s = "Hello";
Затем установите sh другое ссылка на него (как вы делаете со словарем)
string t = s;
Затем «измените оригинальную вещь», изменив эту новую ссылку на что-то другое:
t = "Good bye";
И надеюсь, что оригинал s
изменился. s
по-прежнему указывает на строку с надписью "Hello". t
раньше также указывал на «Hello» (он никогда не указывал на s, указывающий на привет в какой-то цепочке), но теперь указывает на новую строку «Good bye». Мы никогда не использовали ключевое слово new
, когда говорили «До свидания», но компилятор должен был использовать его, и new
создал другой объект и изменил ссылку на него. Поскольку ссылки не связаны друг с другом, вы не можете изменить то, на что указывает нижестоящая переменная, и надеетесь, что переменная обратного потока, указывающая на то же самое, также изменится.
//we had this
s ===> "Hello" <=== t
//not this
t ==> s ==> "Hello"
//then we had this
s ===> "Hello" t ===> "Good bye"
Поскольку у нас есть две независимые ссылки, которые указывают на одну и ту же вещь, единственный способ, которым вы можете работать с одной ссылкой и видеть другую, - это изменение содержимого того, на что они указывают, что означает вам придется использовать что-то изменчивое, а не выбрасывать. Вот где строка путает вещи, потому что строки не могут быть изменены после создания. Они ДОЛЖНЫ быть выброшены и сделаны новые. Вы не видите new
- компилятор сделает это за вас.
Таким образом, вместо использования строк, мы должны использовать что-то вроде строки, но ее содержимое может быть изменено:
StringBuilder sb1 = new StringBuilder("Hello");
StringBuilder sb2 = null;
var d = new Dictionary<string, StringBuilder>();
d["sb1"] = sb1;
d["sb2"] = sb2;
Теперь вы можете изменить строку в изменяемой переменной sb1
, доступ к string Builder через словарь:
d["sb1"].Clear();
d["sb1"].Append("Good bye");
Console.Write(sb1.Length); //prints 8, because it contains: Good bye
Но вы все равно не можете назначить новые ссылки на переменные sb, используя словарь:
d["sb2"] = new StringBuilder("Oh");
//sb2 is still and will always be null
Console.Write(sb2.Length); //null reference exception
Использование new
останавливает словарь, указывающий на sb2
и указывает на что-то еще, sb2
не изменяется и все еще является нулевым. Нет практического способа установить sb2
для экземпляра stringbuilder, используя словарь d
. Именно поэтому оригинальная строковая вещь не сработала - вы не можете изменить содержимое строка - c# выбросит старую строку и сделает new
один и каждый раз, когда new
используется любая ссылка, которая могла бы указывать на старую вещь, теперь будет указывать на новую вещь
В результате вам придется инициализировать все ваши ссылки на что-то заполненное или пустое:
var sb1 = new StringBuilder("Hello");
var sb2 = new StringBuilder("Goodbye");
var sb3 = new StringBuilder("");
var sb4 = new StringBuilder("");
Вам нужно будет связать свой словарь со всеми из них:
d["sb1"] = sb1;
d["sb2"] = sb2;
d["sb3"] = sb3;
d["sb4"] = sb4;
И вам придется пропустить свой словарь в поисках пустого:
//find empty one
for(int i = 1, i <= 4; i++){
if(d["sb"+i].Length ==0)
return "sb"+i;
}
, а затем изменить его содержимое
Это все сложно, и я полностью согласен с ответом дано Джейсоном, который говорит вам использовать массивы (потому что это то, для чего они были изобретены), но я надеюсь, что я ответил на ваши вопросы о том, почему C# не работает так, как вы ожидали