How can I make Array.Contains case-insensitive on a string array?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Array.Contains on strings is case-sensitive by default because it uses the default equality comparer. If you need case-insensitive matching, the correct solution is choosing the right comparer explicitly rather than normalizing strings ad hoc everywhere. The best approach depends on whether you need one-off lookup, repeated lookup, or culture-aware matching.
Use LINQ With a String Comparer
For a simple one-off check, use Enumerable.Contains with a comparer.
StringComparer.OrdinalIgnoreCase is usually the right default for identifiers, codes, and protocol-style strings.
Why OrdinalIgnoreCase Is Usually Best
There are several comparison modes in .NET. The two common ones here are:
- '
StringComparer.OrdinalIgnoreCase' - '
StringComparer.CurrentCultureIgnoreCase'
Use OrdinalIgnoreCase when comparison is technical rather than linguistic. It is predictable and usually faster.
Use culture-aware comparison only when user-facing linguistic behavior actually matters.
Avoid Manual ToLower() and ToUpper()
A common workaround is normalizing both sides with ToLowerInvariant() or ToUpperInvariant(). That works, but it creates extra strings and spreads comparison policy across the codebase.
Less desirable approach:
Cleaner approach:
The comparer-based version is clearer and avoids unnecessary allocations.
Repeated Lookups: Use a HashSet<string>
If you need many case-insensitive lookups, convert the array into a HashSet<string> with the right comparer.
This is much better than repeatedly scanning the whole array if the lookup count is high.
Null Handling
If arrays can contain null, think about the intended behavior. StringComparer handles comparison cleanly, but your surrounding logic still needs to be explicit.
Do not assume null semantics are the same as empty string semantics.
Exact Method Choice Matters
There are two different Contains paths developers often confuse:
- '
Array.IndexOf' - LINQ
Enumerable.Contains
Array.IndexOf does not accept a comparer for strings in the same convenient way. If you need custom comparison semantics, LINQ is usually the more direct choice.
For more custom matching, Any works well:
This is especially useful when additional conditions are needed.
Pick the Right Comparison Rule for the Domain
If strings represent usernames, file extensions, configuration keys, or command names, OrdinalIgnoreCase is usually the safest option. If strings represent human-language text shown to users, evaluate whether culture-aware behavior is actually required.
Do not choose the comparison rule casually. Equality semantics are part of your data contract.
Common Pitfalls
One common mistake is using ToLower() everywhere instead of one explicit comparer-based rule. Another is using culture-aware comparison for non-linguistic identifiers, which can create surprising behavior. Developers also keep arrays for repeated lookups when a HashSet<string> would be more appropriate. Null values are frequently ignored until an edge case appears. Finally, teams often mix different comparison rules in different modules and get inconsistent behavior.
Summary
- '
Array.Containson strings is case-sensitive by default.' - Use LINQ
ContainswithStringComparer.OrdinalIgnoreCasefor one-off case-insensitive checks. - Prefer comparer-based logic over manual case normalization.
- Use
HashSet<string>with a comparer for repeated lookups. - Choose comparison semantics based on domain needs, not convenience.
- Keep null handling and string comparison policy explicit.

