C# Strings
A string is C#’s main type for storing and working with text. Names, messages, file paths, user input, JSON, and console output all use strings somewhere. Learning strings well matters because text looks simple, but details like immutability, escaping, casing, and comparison rules affect correctness and performance.
Overview: How C# Strings Work
In C#, string is an alias for the .NET type System.String. It is a reference type, but it behaves like a value in many everyday situations because strings are immutable: once a string object is created, its characters cannot be changed. Operations such as ToUpper(), Replace(), or concatenation create a new string instead of editing the old one.
A string is a sequence of char values. A char in .NET is a 16-bit UTF-16 code unit, which means most common characters fit in one char, but some Unicode characters, such as many emoji or historic scripts, may require two char values called a surrogate pair. For beginner work, indexing a string by position often feels like indexing characters, but for full Unicode text you should remember that one visible symbol is not always one char.
String literals are written between double quotes, such as "Hello". C# also supports escape sequences like \n for a newline and \" for a quote inside a string. Verbatim strings start with @ and treat backslashes as normal characters, which is useful for Windows paths. Interpolated strings start with $ and allow expressions inside braces. You can combine both as $@"..." or @$"...".
Because strings are so common, the C# compiler and CLR optimize them heavily. Literal strings may be interned, meaning identical literals can refer to the same object in memory. You should not rely on that for program logic; compare string contents with ==, Equals, or methods such as String.Equals with a StringComparison option. In C#, == on strings compares text content, not just object identity.
Syntax
string name = "Ada";
string message = $"Hello, {name}!";
int length = message.Length;
char first = message[0];
string changed = message.Replace("Hello", "Hi");
| Syntax | Meaning |
|---|---|
"text" |
A regular string literal. |
"Line 1\nLine 2" |
A string containing an escape sequence. |
@"C:\Users\Ada" |
A verbatim string where backslashes are ordinary characters. |
$"Hi {name}" |
An interpolated string that inserts expression values. |
text.Length |
The number of UTF-16 char values in the string. |
text[index] |
Reads the char at a zero-based index. |
text.Substring(start, count) |
Creates a new string from part of another string. |
The variable type is string, the variable name is chosen by you, and the value is usually a literal, another string expression, or a method result. String methods return values, so assign the result when you want to keep the changed text.
Examples
Creating and Combining Strings
using System;
class Program
{
static void Main()
{
string firstName = "Grace";
string lastName = "Hopper";
string fullName = firstName + " " + lastName;
string greeting = $"Welcome, {fullName}!";
Console.WriteLine(fullName);
Console.WriteLine(greeting);
Console.WriteLine($"Characters: {fullName.Length}");
}
}
Output:
Grace Hopper
Welcome, Grace Hopper!
Characters: 12
The + operator joins strings together. Interpolation is often clearer when text and variables are mixed, because each expression appears where its value will be placed. Length counts the characters in Grace Hopper, including the space.
Escapes, Verbatim Strings, and Quotes
using System;
class Program
{
static void Main()
{
string twoLines = "First line\nSecond line";
string path = @"C:\Course\cs\strings.txt";
string quote = "She said, \"Keep practicing.\"";
Console.WriteLine(twoLines);
Console.WriteLine(path);
Console.WriteLine(quote);
}
}
Output:
First line
Second line
C:\Course\cs\strings.txt
She said, "Keep practicing."
The newline escape \n becomes an actual line break. The verbatim string keeps each backslash in the path without needing \\. The quote inside quote is escaped so the compiler knows it belongs inside the string instead of ending it.
Searching, Slicing, and Changing Text
using System;
class Program
{
static void Main()
{
string email = "maya.chen@example.com";
int atIndex = email.IndexOf('@');
string userName = email.Substring(0, atIndex);
string domain = email.Substring(atIndex + 1);
string displayName = userName.Replace('.', ' ');
Console.WriteLine($"User: {displayName}");
Console.WriteLine($"Domain: {domain}");
Console.WriteLine($"Ends with .com: {email.EndsWith(".com")}");
}
}
Output:
User: maya chen
Domain: example.com
Ends with .com: True
IndexOf finds the position of a character. Substring creates new strings from ranges of the original email. Replace also returns a new string; the original email is unchanged.
Building Many Pieces Efficiently
using System;
using System.Text;
class Program
{
static void Main()
{
string[] tasks = { "Read", "Practice", "Review" };
StringBuilder builder = new StringBuilder();
for (int i = 0; i < tasks.Length; i++)
{
builder.Append(i + 1);
builder.Append(". ");
builder.AppendLine(tasks[i]);
}
Console.Write(builder.ToString());
}
}
Output:
1. Read
2. Practice
3. Review
Repeated string concatenation inside loops can create many temporary string objects. StringBuilder stores a growable buffer, so it is the usual choice when building text gradually from many pieces.
How Strings Work Step by Step
- The compiler sees a string literal such as
"Ada"and records it as string metadata in the compiled assembly. - At runtime, the CLR creates or reuses an immutable
System.Stringobject containing that text. - When your code reads
text[0], .NET returns thecharat zero-based position0. The string object itself is not changed. - When your code calls
text.Replace("a", "o"), .NET scans the old string and returns a new string containing the replacement result. - If no variable stores that new string, the result is eventually discarded and the original string remains exactly as it was.
This design makes strings safe to share. If two variables refer to the same string object, one part of the program cannot secretly modify the text for the other part. The tradeoff is that heavy text editing can allocate many objects unless you use tools such as StringBuilder.
Common Mistakes
Trying to Modify a Character In Place
string word = "cat";
word[0] = 'b';
This does not compile because strings are immutable and the indexer is read-only. Create a new string instead.
using System;
class Program
{
static void Main()
{
string word = "cat";
string changed = "b" + word.Substring(1);
Console.WriteLine(changed);
}
}
Output:
bat
Forgetting That Methods Return New Strings
using System;
class Program
{
static void Main()
{
string title = "c# strings";
title.ToUpper();
Console.WriteLine(title);
title = title.ToUpper();
Console.WriteLine(title);
}
}
Output:
c# strings
C# STRINGS
The first ToUpper() result is ignored, so title still points to the original text. The second call assigns the returned string back to title.
Using Culture-Sensitive Comparisons Accidentally
using System;
class Program
{
static void Main()
{
string savedCode = "FILE";
string typedCode = "file";
bool sameCode = string.Equals(savedCode, typedCode, StringComparison.OrdinalIgnoreCase);
Console.WriteLine(sameCode);
}
}
Output:
True
For identifiers, codes, file-like keys, protocol values, and other non-linguistic text, prefer ordinal comparisons. They compare Unicode values directly and avoid surprises from human-language casing rules.
Best Practices
- Prefer
stringoverSystem.Stringin ordinary C# code; they mean the same type, butstringmatches common style. - Use interpolation for readable messages, especially with more than one value.
- Remember that string indexes are zero-based and that
Lengthis a count, not the last valid index. - Assign the result of methods such as
Trim(),Replace(),ToLower(), andToUpper()when you want the changed text. - Use
StringComparison.OrdinalorStringComparison.OrdinalIgnoreCasefor technical identifiers and exact program data. - Use
StringBuilderwhen a loop builds a large string from many smaller parts. - Check for missing text with
string.IsNullOrEmptyorstring.IsNullOrWhiteSpaceinstead of comparing only to"". - Be careful with user-visible Unicode text: a visible character can be more than one
char.
Practice Exercises
- Create variables for a first name and last name. Print the full name, the total length, and the first character of the last name.
- Given
" learn C# strings ", trim the spaces, replaceC#withCSharp, and print the final result. - Write a small program that takes three words stored in an array and uses
StringBuilderto print them as a numbered list.
Summary
stringis C#’s standard type for text and is an alias forSystem.String.- Strings are immutable, so methods and concatenation create new strings.
- Use escapes, verbatim strings, and interpolation to write readable string literals.
Length, indexing,IndexOf,Substring,Replace, and casing methods are everyday string tools.- Choose explicit comparison rules when string equality affects program behavior.
- Use
StringBuilderfor repeated text construction in loops.
