Normalize Strings

ID

csharp.normalize_strings

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

CSharp

Tags

culture, reliability, string

Description

Reports ToLowerInvariant() and ToUpperInvariant() calls on string receivers. These methods sound culture-safe but still apply Unicode casing transforms that produce surprises with the Turkish dotted-i family and a few other characters.

Rationale

When two strings need to be compared case-insensitively the .NET-recommended pattern is to call String.Equals(other, StringComparison.OrdinalIgnoreCase) directly. Casing the string and then comparing materialises an extra allocation and can still misbehave for characters whose invariant casing is not idempotent.

public class Norm
{
    public bool MatchUpper(string a, string b)
    {
        return a.ToUpperInvariant() == b.ToUpperInvariant();                     // FLAW (twice)
    }

    public bool MatchLower(string a, string b)
    {
        return a.ToLowerInvariant().Equals(b);                                   // FLAW
    }

    public bool MatchOrdinal(string a, string b)
    {
        return a.Equals(b, StringComparison.OrdinalIgnoreCase);                  // OK
    }
}

Remediation

Replace a.ToLowerInvariant() == b.ToLowerInvariant() with String.Equals(a, b, StringComparison.OrdinalIgnoreCase). When a normalized form is genuinely required (Unicode normalization for storage), call Normalize(NormalizationForm.FormC) followed by casing under CultureInfo.InvariantCulture.