LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 1618 min read

Strings

Learn how to work with strings in C# — concatenation, interpolation, common methods, and StringBuilder.

Strings Are Immutable

Once a string is created, it can never be changed for the rest of its lifetime. Every method that appears to modify a string — like `ToUpper()` or `Replace()` — actually returns a brand new string object, leaving the original completely untouched.

string original = "hello";
string upper = original.ToUpper();
Console.WriteLine(original); // "hello" — unchanged
Console.WriteLine(upper); // "HELLO" — a new string

Common String Methods

MethodPurpose
.LengthNumber of characters
.ToUpper() / .ToLower()Change case
.Trim() / .TrimStart() / .TrimEnd()Remove leading/trailing whitespace
.Substring(start, length)Extract part of a string
.Split(char)Split into an array of strings
.Replace(old, new)Replace all occurrences of a substring
.Contains(value)Check if a substring exists
.StartsWith() / .EndsWith()Check the beginning or end of a string
.IndexOf(value)Find the position of a substring, or -1 if not found
.PadLeft(n) / .PadRight(n)Pad a string to a fixed width
string sentence = " Hello, C# World! ";
Console.WriteLine(sentence.Trim().ToUpper());
Console.WriteLine(sentence.Contains("C#"));
Console.WriteLine(sentence.Trim().StartsWith("Hello"));
Console.WriteLine("7".PadLeft(3, '0')); // "007"
Output

Click Run to see what this code prints.

Concatenation & Interpolation

As covered in the input/output lesson, string interpolation is the modern, preferred approach — it reads more naturally and handles formatting and alignment directly, without the visual clutter of many + operators.

string first = "Jane";
string last = "Doe";
string full1 = first + " " + last; // concatenation — works, but less readable at scale
string full2 = $"{first} {last}"; // interpolation (preferred)
Console.WriteLine(full2);

Comparing Strings

Unlike most reference types, == on strings compares their actual content, not just whether they're the same object in memory — a deliberate, useful exception to normal reference-type equality behavior.

string a = "hello";
string b = "HELLO";
Console.WriteLine(a == b); // False — case-sensitive by default
Console.WriteLine(string.Equals(a, b, StringComparison.OrdinalIgnoreCase)); // True
Fun Fact

string.Equals with an explicit StringComparison argument is generally considered best practice over == in production code, since it forces you to consciously decide whether the comparison should be case-sensitive, culture-aware, or ordinal — a decision == silently makes for you (case-sensitive, ordinal) without making that choice visible.

Splitting & Joining

Split() breaks a string into an array based on a delimiter; string.Join() does the reverse, combining an array (or any collection) back into one string with a separator.

string csv = "Alice,Bob,Charlie";
string[] names = csv.Split(',');
Console.WriteLine(names.Length); // 3
Console.WriteLine(names[1]); // Bob
string rejoined = string.Join(" & ", names);
Console.WriteLine(rejoined); // Alice & Bob & Charlie

StringBuilder

Because strings are immutable, building one up in a loop with `+=` creates a brand new string object on every single iteration — for a small number of iterations this is invisible, but for hundreds or thousands, it wastes significant memory and time. `StringBuilder` mutates an internal, resizable buffer instead, which is far more efficient for repeated appends.

using System.Text;
var sb = new StringBuilder();
for (int i = 1; i <= 3; i++)
{
sb.Append($"Line {i}\n");
}
Console.WriteLine(sb.ToString());
When to Use StringBuilder

Reach for StringBuilder when building a string inside a loop with many iterations (dozens or more). For a handful of concatenations, regular strings and interpolation are perfectly fine and more readable — StringBuilder itself has a small amount of overhead that isn't worth it for trivial cases.

StringBuilder also supports several other useful methods beyond Append.

MethodPurpose
.Append(value)Adds text to the end
.AppendLine(value)Adds text followed by a newline
.Insert(index, value)Inserts text at a specific position
.Remove(start, length)Removes a range of characters
.Replace(old, new)Replaces text within the buffer
.ToString()Converts the buffer to a final, regular string

Common Beginner Mistakes

Expecting a string method to modify the original variable

text.Trim(); on its own does nothing useful — the result must be captured: text = text.Trim();, since strings can never be modified in place.

Building a large string with += inside a loop

This creates a new string object on every iteration — use StringBuilder for anything beyond a small, fixed number of concatenations.

Assuming string comparison is always case-insensitive

== and string.Equals() default to case-sensitive comparison — explicitly pass StringComparison.OrdinalIgnoreCase when case shouldn't matter.

FAQs

Use `string.Equals(a, b, StringComparison.OrdinalIgnoreCase)` rather than converting both to the same case first with ToUpper()/ToLower(), which creates unnecessary intermediate string objects.

Conceptually yes — interpolation ($"...") is newer, more readable syntax that compiles down to essentially the same mechanism as string.Format("{0}", value); both support the same format specifiers.

It throws an ArgumentOutOfRangeException — always ensure start + length doesn't exceed the string's actual Length before calling Substring on untrusted input.

Yes — "" is a valid, zero-length string object; null means no string object exists at all. string.IsNullOrEmpty() and string.IsNullOrWhiteSpace() check for both cases at once, which is usually what you actually want.

Key Takeaways

  • Strings are immutable — every "modifying" method returns a new string, never changing the original.
  • Prefer string interpolation ($"...") over manual + concatenation for readability.
  • Use string.Equals with an explicit StringComparison for comparisons where case-sensitivity matters.
  • Use StringBuilder for building large strings inside loops with many iterations.

Summary

Strings are one of the most frequently used types in any real program, and understanding their immutability — plus when to reach for StringBuilder — will make your code both correct and efficient. Next, you'll learn how to organize reusable logic into methods.

Next Lesson →

Methods