StringComparison.InvariantCulture is not always invariant

 
 
  • Gérald Barré

CultureInfo.InvariantCulture is not invariant for all operations. It is a special culture that is used for formatting and parsing operations that do not depend on any specific culture. For instance, this is well-suited to format values in order to persist them. However, it is not invariant for string comparisons. Comparing strings using InvariantCulture can lead to different results depending on the current version of NLS or ICU used by the .NET runtime.

If you look at the code of .NET, only the CultureData is invariant: https://github.com/dotnet/runtime/blob/64252fba0225d92164875824a70b40cc86b7b063/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs#L546-L655.

C#
// Invariant (formatting / parsing)
var value = -42;
_ = value.ToString("C", CultureInfo.InvariantCulture);
_ = int.Parse("-42", CultureInfo.InvariantCulture);

// Not invariant (comparisons, may produce different results)
string a  = "...";
string b  = "...";
_ = string.Equals(a, b, StringComparison.InvariantCulture);
_ = StringComparer.InvariantCulture.Compare(a, b);

StringComparison.InvariantCulture or StringComparer.InvariantCulture usages are wrong most of the time and should be replaced with Ordinal comparisons. In my coding standards, the 2 symbols are banned using Microsoft.CodeAnalysis.BannedApiAnalyzers and the following configuration:

BannedSymbols.txt
F:System.StringComparison.InvariantCulture;Do you mean Ordinal?
F:System.StringComparison.InvariantCultureIgnoreCase;Do you mean OrdinalIgnoreCase?
P:System.StringComparer.InvariantCulture;Do you mean Ordinal?
P:System.StringComparer.InvariantCultureIgnoreCase;Do you mean OrdinalIgnoreCase?

Note that you can use App-local ICU to fix the version of ICU and get consistent behavior across different environments. This is especially useful when you need to ensure that your application behaves the same way regardless of the system's locale settings.

Another way is to use the Globalization Invariant Mode, which is a mode that allows you to run .NET applications without relying on the underlying operating system's globalization features. This can be useful in scenarios where you want to ensure consistent behavior across different platforms or when you want to reduce the size of your application by not including the full globalization data. Note that this mode is not equivalent to using Ordinal when comparing strings.

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub