Strings

A string is a sequence of characters — names, messages, file contents, JSON. C# strings are objects with dozens of useful methods, but they have one defining property: they can never be changed after they're created. This lesson covers creating strings, the different kinds of string literal, indexing, immutability and empty values.

Creating strings

C#
string greeting = "Hello";
string empty = "";
string repeated = new string('=', 12);
string fromChars = new string(['C', '#']);

Console.WriteLine(greeting);
Console.WriteLine($"[{empty}]");
Console.WriteLine(repeated);
Console.WriteLine(fromChars);
Output
Hello
[]
============
C#

Length and characters

Length is the number of characters. Square brackets read a single char by position, starting at 0; ^1 counts from the end (lesson 30):

C#
string word = "Banana";

Console.WriteLine(word.Length);
Console.WriteLine(word[0]);
Console.WriteLine(word[word.Length - 1]);
Console.WriteLine(word[^1]);
Console.WriteLine(word[1..4]);   // characters 1, 2 and 3

foreach (char c in word)
{
    Console.Write(c + "-");
}
Console.WriteLine();
Output
6
B
a
a
ana
B-a-n-a-n-a-

Strings are immutable

You can't change a character inside a string. Methods that seem to modify a string — ToUpper, Replace, Trim — return a new string and leave the original untouched:

C#
string name = "sam";
name[0] = 'S';
Build error
Program.cs(2,1): error CS0200: Property or indexer 'string.this[int]' cannot be assigned to -- it is read only
C#
string name = "sam";
name.ToUpper();                   // result thrown away!
Console.WriteLine(name);

name = name.ToUpper();            // keep the new string
Console.WriteLine(name);

string title = char.ToUpper(name[0]) + name[1..].ToLower();
Console.WriteLine(title);
Output
sam
SAM
Sam

Immutability makes strings safe to share between variables and threads. The cost is that building a long string piece by piece creates many temporary strings — lesson 19's StringBuilder solves that.

Joining strings

You can join strings with +, but interpolation is usually clearer: put $ before the quotes and write expressions in braces:

C#
string first = "Ada";
string last = "Lovelace";
int born = 1815;

string a = first + " " + last + " was born in " + born + ".";
string b = $"{first} {last} was born in {born}.";
string c = string.Concat(first, " ", last);
string d = string.Join(", ", "red", "green", "blue");

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
Console.WriteLine($"{first.Length + last.Length} letters, initials {first[0]}{last[0]}");
Output
Ada Lovelace was born in 1815.
Ada Lovelace was born in 1815.
Ada Lovelace
red, green, blue
11 letters, initials AL

Verbatim strings

Prefix a string with @ and backslashes are no longer escape characters. That's convenient for Windows paths and regular expressions. To include a double quote, write it twice:

C#
string path1 = "C:\\Users\\mira\\notes.txt";
string path2 = @"C:\Users\mira\notes.txt";
string quote = @"She said ""hello"".";

Console.WriteLine(path1 == path2);
Console.WriteLine(path2);
Console.WriteLine(quote);
Output
True
C:\Users\mira\notes.txt
She said "hello".

Raw string literals

For text containing quotes, backslashes or several lines — JSON, SQL, HTML — use a raw string literal: three (or more) double quotes. Nothing inside is escaped, and the indentation of the closing quotes is removed from every line:

C#
string json = """
    {
      "name": "Widget",
      "path": "C:\temp",
      "tags": ["new", "sale"]
    }
    """;
Console.WriteLine(json);
Output
{
  "name": "Widget",
  "path": "C:\temp",
  "tags": ["new", "sale"]
}

Raw strings can be interpolated too. Add one $ per brace you want to use for values — with $$, single braces stay literal and {{ }} marks a value:

C#
string product = "Widget";
decimal price = 9.5m;

string json = $$"""
    { "name": "{{product}}", "price": {{price}} }
    """;
Console.WriteLine(json);
Output
{ "name": "Widget", "price": 9.5 }

Comparing strings

== compares the characters, case-sensitively. For other comparisons, pass a StringComparison:

C#
string a = "Hello";
string b = "hello";

Console.WriteLine(a == b);
Console.WriteLine(a.Equals(b, StringComparison.OrdinalIgnoreCase));
Console.WriteLine(string.Compare("apple", "banana", StringComparison.Ordinal) < 0);
Console.WriteLine("Zebra".CompareTo("apple"));
Output
False
True
True
1

Compare and CompareTo return a negative number, zero or a positive number for "before", "equal" and "after" — the basis of sorting. Ordinal compares character codes and is fast and predictable; culture-aware comparison (the default for CompareTo) follows the alphabet rules of a language, which is what you want when sorting names for display.

Empty, whitespace and null

A string variable can hold text, the empty string "", or no string at all (null, if declared as string?). Two helper methods test for "nothing useful":

C#
string?[] values = ["text", "", "   ", null];

foreach (string? v in values)
{
    Console.WriteLine($"[{v}] empty: {string.IsNullOrEmpty(v)}, blank: {string.IsNullOrWhiteSpace(v)}");
}
Output
[text] empty: False, blank: False
[] empty: True, blank: True
[   ] empty: False, blank: True
[] empty: True, blank: True

IsNullOrWhiteSpace is the right check for form fields and user input. string.Empty is another way to write "".

Unicode and Length

A char is a 16-bit UTF-16 code unit. Most characters fit in one, but emoji and some rarer characters need two, so Length counts code units, not what a reader would call characters:

C#
string word = "café";
string emoji = "👍";

Console.WriteLine(word.Length);
Console.WriteLine(emoji.Length);
Console.WriteLine(new System.Globalization.StringInfo(emoji).LengthInTextElements);
Output
4
2
1

For everyday text this rarely matters, but keep it in mind when truncating strings for display.

Try it yourself

Build initials and a username from a full name.

Try it yourself · Program.cs
Edit the code, copy it into Program.cs and run it with dotnet run Program.cs (.NET 10 or later). How to set up .NET
Output
Initials: GBH
Username: grace.hopper
Name length: 21