Need to know if a name, email or code has a certain letter in it? In C#, text.Contains('M') answers that in one call and returns true or false.
In this tutorial, I’ll walk one customer name, Jenna Morales, through each C# string contains character check worth knowing on .NET 10:
string customer = "Jenna Morales";
Console.WriteLine(customer.Contains('M'));
Console.WriteLine(customer.Contains('z'));
Output:
True
False
'M' is in “Jenna Morales”, so the first line prints True. There’s no 'z', so the second prints False.
String.Contains(char) Syntax and Overloads in C#
The single quotes matter: 'M' is a char, while "M" is a one-character string. Both work, but each one picks a different overload (see C# data types for how char differs from string).
| Method | Returns | Available in |
|---|---|---|
Contains(char) | bool | .NET Core 2.1+, .NET 5-10 |
Contains(char, StringComparison) | bool | .NET Core 2.1+, .NET 5-10 |
Contains(string) | bool | All versions, incl. .NET Framework |
IndexOf(char) | int (-1 if missing) | All versions, incl. .NET Framework |
Microsoft’s analyzer rule CA1847 flags Contains("M") and suggests Contains('M'), because the char overload is faster.
On .NET Framework 4.8 there’s no char overload, so use IndexOf('M') >= 0 there. Not sure which runtime you’re on? Here’s how to check your .NET version.
How Do You Check If a String Contains a Character Ignoring Case?
Contains(char) is ordinal, which means case-sensitive. Same name, now looking for a lowercase 'm':
string customer = "Jenna Morales";
Console.WriteLine(customer.Contains('m'));
Console.WriteLine(customer.Contains('m', StringComparison.OrdinalIgnoreCase));
Console.WriteLine(customer.Contains("M"));
// Older way: lower-case the char and the string first
char wanted = 'J';
Console.WriteLine(customer.ToLowerInvariant().Contains(char.ToLowerInvariant(wanted)));
Output:
False
True
True
True

The plain call prints False because the name only has a capital M. Passing StringComparison.OrdinalIgnoreCase flips it to True.
The last line is the old trick: lower-case both sides with ToLowerInvariant. It works on any version, but it allocates a new string, so I only use it on .NET Framework.
Find the Character’s Position with IndexOf and LastIndexOf
When you need to know where the character is, not just whether it’s there, switch to IndexOf:
string customer = "Jenna Morales";
int first = customer.IndexOf('a');
int last = customer.LastIndexOf('a');
int missing = customer.IndexOf('z');
Console.WriteLine($"First 'a' at {first}, last 'a' at {last}");
Console.WriteLine($"'z' at {missing}, found: {missing >= 0}");
Console.WriteLine($"Space at {customer.IndexOf(' ')}");
Console.WriteLine($"First name: {customer[..customer.IndexOf(' ')]}");
Output:
First 'a' at 4, last 'a' at 9
'z' at -1, found: False
Space at 5
First name: Jenna

The first 'a' sits at index 4 and the last at 9, since indexes start at 0. 'z' returns -1, so IndexOf(c) >= 0 is the classic contains check.
The space at index 5 lets the range customer[..5] cut out “Jenna”. It’s the same idea I use to get the first N characters of a string.
Check for Any of Several Characters with IndexOfAny, ContainsAny and SearchValues
Validation usually asks a different question: does this username contain any forbidden character? Here are four usernames checked against @, #, $ and a space:
using System.Buffers;
string[] usernames = ["jenna.morales", "tyler#brooks", "maria_lopez", "evan@reed"];
char[] bad = ['@', '#', '$', ' '];
SearchValues<char> badSet = SearchValues.Create("@#$ ");
foreach (string user in usernames)
{
int at = user.IndexOfAny(bad);
bool spanHit = user.AsSpan().ContainsAny(badSet);
Console.WriteLine($"{user,-14} IndexOfAny={at,2} ContainsAny={spanHit}");
}
string evan = "evan@reed";
Console.WriteLine(evan.Contains('@'));
Console.WriteLine(evan.IndexOf('@'));
Console.WriteLine(evan.AsSpan().ContainsAny('@', '#'));
Output:
jenna.morales IndexOfAny=-1 ContainsAny=False
tyler#brooks IndexOfAny= 5 ContainsAny=True
maria_lopez IndexOfAny=-1 ContainsAny=False
evan@reed IndexOfAny= 4 ContainsAny=True
True
4
True

tyler#brooks fails at index 5 and evan@reed at index 4. The other two pass with -1 and False.
IndexOfAny(char[]) works on every .NET version. AsSpan().ContainsAny needs .NET 8+, and SearchValues.Create builds an optimized set you should create once and reuse, ideally in a static readonly field.
For two or three characters, ContainsAny('@', '#') skips the set entirely. If you’re matching whole words instead of characters, see how to compare a string with multiple values.
Note: Regex.IsMatch(user, "[@#$ ]") gives the same answer, but a regex is overkill for a fixed character list.
Count Character Occurrences with LINQ Any and Count
LINQ helps when the question is a category, like “any digit?”, or a count. Here’s a US city line with a ZIP code:
string zipLine = "Austin, TX 78701";
Console.WriteLine(zipLine.Any(char.IsDigit));
Console.WriteLine(zipLine.Any(char.IsLower));
Console.WriteLine(zipLine.All(c => c != '!'));
int digits = zipLine.Count(char.IsDigit);
int ts = zipLine.Count(c => c == 'T' || c == 't');
Console.WriteLine($"Digits: {digits}, T or t: {ts}");
Console.WriteLine($"Spaces: {zipLine.AsSpan().Count(' ')}");
Output:
True
True
True
Digits: 5, T or t: 2
Spaces: 2

Any(char.IsDigit) returns True, and Count finds 5 digits and 2 Ts in “Austin, TX 78701”. All(c => c != '!') is the reverse check: no exclamation mark anywhere.
For one exact character, AsSpan().Count(' ') (.NET 8+) counts the 2 spaces without LINQ. Under the hood, LINQ just walks the string like a foreach loop in C# would.
Null-Safe Contains Check (and the Errors to Avoid)
Real input can be empty or null. Calling Contains on a null string throws, so guard it with ?. and ?? false:
string?[] inputs = ["Tyler Brooks", "", null];
foreach (string? s in inputs)
{
bool hasSpace = s?.Contains(' ') ?? false;
string shown = s is null ? "null" : $"\"{s}\"";
Console.WriteLine($"{shown,-15} has a space: {hasSpace}");
}
string? missing = null;
try { Console.WriteLine(missing!.Contains(' ')); }
catch (NullReferenceException) { Console.WriteLine("NullReferenceException"); }
try { Console.WriteLine("Tyler".Contains((string)null!)); }
catch (ArgumentNullException ex) { Console.WriteLine(ex.GetType().Name); }
Output:
"Tyler Brooks" has a space: True
"" has a space: False
null has a space: False
NullReferenceException
ArgumentNullException

“Tyler Brooks” has a space, while the empty string and null both return False. Without the guard, missing.Contains(' ') throws NullReferenceException.
There’s a second trap: passing a null argument to Contains(string) throws ArgumentNullException, caught here with a try-catch block. To test the string itself first, check if a string is not null or empty.
Working on more string checks? These pair well with this one:
- Check if a string array contains a specific element
- Remove a particular character from a string in C#
- Remove the last character from a string
- Compare two strings character by character
Frequently Asked Questions
How do I check if a string contains a character in C#?
Call text.Contains('x') with a char in single quotes. It returns true if the character appears anywhere in the string and false if it doesn’t.
Is String.Contains case-sensitive in C#?
Yes. Contains(char) and Contains(string) do an ordinal, case-sensitive comparison. Pass StringComparison.OrdinalIgnoreCase as the second argument to ignore case.
Why is there no Contains(char) in .NET Framework?
The char overload arrived in .NET Core 2.1, so .NET Framework 4.8 only has Contains(string). Use text.IndexOf('x') >= 0 there. The String.Contains reference on Microsoft Learn lists every overload and version.
How do I check if a string contains any of several characters?
Use text.IndexOfAny(new[] { '@', '#' }) >= 0 on any version, or text.AsSpan().ContainsAny('@', '#') on .NET 8 and later. For a set you reuse often, create a SearchValues<char> once.
How do I count how many times a character appears in a string?
Use LINQ: text.Count(c => c == 'a'). On .NET 8+, text.AsSpan().Count('a') does the same without a lambda.
What happens if I call Contains on a null string?
It throws NullReferenceException. Write text?.Contains('x') ?? false to get false for null instead.
Bijay Kumar is a renowned software engineer, accomplished author, and distinguished Microsoft Most Valuable Professional (MVP) specializing in SharePoint. With a rich professional background spanning over 15 years, Bijay has established himself as an authority in the field of information technology. He possesses unparalleled expertise in multiple programming languages and technologies such as ASP.NET, ASP.NET MVC, C#.NET, and SharePoint, which has enabled him to develop innovative and cutting-edge solutions for clients across the globe. Read more…