How to make String.Contains case insensitive?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A case-insensitive substring check sounds simple, but the details matter in C#. The best solution depends on your target framework and on whether you want ordinal comparison semantics or culture-aware text behavior.
The modern solution in C#
In current .NET versions, string.Contains has an overload that accepts StringComparison. This is usually the cleanest and most efficient answer.
StringComparison.OrdinalIgnoreCase is often the right default for identifiers, protocol values, file extensions, and most programmatic matching. It performs a case-insensitive comparison based on Unicode code points rather than user-locale sorting rules.
When to use culture-aware comparisons
If the comparison is part of user-facing text behavior, you may want CurrentCultureIgnoreCase or InvariantCultureIgnoreCase instead.
The important point is intent. Ordinal comparisons are best for machine-style matching. Culture-aware comparisons are for human language scenarios such as UI search or localized text processing.
Older framework fallback
If your target framework does not support the Contains overload, use IndexOf with StringComparison and check whether the result is non-negative.
This is the traditional fallback and still a perfectly valid approach.
Why ToLower() and ToUpper() are weaker solutions
A common workaround is to normalize both strings with ToLower() or ToUpper() and then call Contains. That works in simple cases, but it is usually a worse choice.
The issues are:
- it allocates new strings
- it can hide culture-related bugs
- it is less explicit about comparison intent
Passing StringComparison directly avoids those extra allocations and expresses the rule more clearly.
Null handling and reusable helpers
If the source string or search value may be null, decide that behavior explicitly instead of letting random call sites handle it differently.
A helper like this prevents ad hoc mixes of ordinal, invariant, and culture-sensitive rules across the codebase.
Test the comparison mode you choose
Because string comparison rules affect behavior in subtle ways, it is worth writing a small unit test around whichever mode you standardize on.
A tiny test like this makes framework upgrades or helper refactors much safer.
Common Pitfalls
The most common mistake is using ToLower() or ToUpper() everywhere without deciding which comparison semantics are actually required. This can produce subtle bugs in internationalized applications.
Another problem is choosing a culture-aware comparison for machine identifiers. For keys, tokens, MIME types, and file names, OrdinalIgnoreCase is usually the safer choice.
It is also easy to forget framework compatibility. If your project targets an older runtime, the Contains overload may not exist, and IndexOf becomes the compatible option.
Summary
- In modern C#, use
string.Contains(value, StringComparison.OrdinalIgnoreCase)for most case-insensitive substring checks. - Use culture-aware comparisons only when text behavior should follow language rules.
- On older frameworks, use
IndexOf(..., StringComparison...) >= 0. - Avoid normalizing with
ToLower()orToUpper()unless you have a specific reason. - Pick one comparison strategy deliberately instead of mixing several by accident.

