What immutable means
A C# string is immutable: once it has been created, none of its characters can change. Reading a character with an index is fine, but writing to one is not.
string message = "Jello world";
char first = message[0]; // fine: reading gives 'J'
message[0] = 'H'; // compile error
The second line does not compile. The indexer on a string is read-only, and the compiler reports that string.this[int] cannot be assigned to.
The variable can still change
Immutability applies to the string value, not to the variable that refers to it. A variable can be pointed at a different string at any time:
string message = "Jello world";
message = "Hello world";
Console.WriteLine(message); // Hello world
This does not edit the first string. It creates a second string, "Hello world", and makes message refer to it. The old string is left alone, and the runtime discards it later if nothing else uses it.
Because the old string is untouched, another variable that referred to it keeps its value:
string a = "abc";
string b = a;
a += "d";
Console.WriteLine(a); // abcd
Console.WriteLine(b); // abc
Here a += "d" creates a new string and points a at it. The variable b still refers to "abc". This is a big part of why immutability is useful: nobody can change a string out from under you.
Methods return new strings
Every method that seems to modify a string actually returns a new one and leaves the original as it was. This is a common source of bugs:
string word = "hello";
word.ToUpper(); // result thrown away
Console.WriteLine(word); // hello
word = word.ToUpper(); // keep the result
Console.WriteLine(word); // HELLO
The first call produces "HELLO" and then discards it. If you want the change, assign the result back to a variable. The same goes for Replace, Trim, Substring and the rest.
Building a changed copy
To "change" one character, build a new string out of the pieces you want to keep. Substring(1) returns every character except the first, and + joins strings into a new one:
string word = "jello";
word = "H" + word.Substring(1);
Console.WriteLine(word); // Hello
When you need to change many characters, creating a new string every time gets wasteful. Then StringBuilder or a char[] is the usual tool, because both can be edited in place:
using System.Text;
StringBuilder builder = new StringBuilder("jello");
builder[0] = 'H';
Console.WriteLine(builder.ToString()); // Hello
The StringBuilder is a separate, mutable object. Calling ToString() turns its contents back into an ordinary string.
Why strings are immutable
Immutability makes strings safe to share. Many parts of a program can hold the same string without worrying that one of them will change it for the rest. It also lets the runtime reuse identical string literals, and it makes strings dependable as dictionary keys, because a key's contents can never change after it has been stored.
The cost is that each "change" allocates a new string. For a handful of edits that is nothing to worry about. Inside a loop that appends thousands of times, it adds up, which is when StringBuilder pays off.
The exercise, step by step
The lesson starts with a name that has a typo: name holds "bndrei Chiriac", and the fix has to produce "Andrei Chiriac". The starter line, name[0] = 'A';, tries to overwrite the first character, which is not allowed.
- Drop the wrong first character.
name.Substring(1)returns"ndrei Chiriac", which is the name without its first character. - Put the right one in front. Joining
"A"and that result with+gives"Andrei Chiriac". - Assign it back to
name. The variable now refers to the corrected string.
string name = "bndrei Chiriac";
// Change code below:
name = "A" + name.Substring(1);
The "A" is a string in double quotes, so + joins two strings. Single quotes would make it a char, which is a different type. The assignment is also why the code compiles: it gives name a brand new string rather than editing the old one.
Common mistakes
- Assigning to an index.
name[0] = 'A'never compiles, whatever the value. - Ignoring the returned string. Calling
name.Substring(1)on its own line changes nothing, because the result is not stored. - Mixing up
Substring(0)andSubstring(1).Substring(0)returns the whole string, so the typo would stay in.
Key takeaways
- Strings are immutable: their characters can be read but not assigned.
- A variable can be reassigned to a new string at any time.
- String methods return new strings, so store the result if you need it.
- To change part of a string, build a new one from pieces with
Substringand+.