A common globalization bug

I’ve just found and fixed a globalization bug in our test infrastructure where a feature of our testcase management system (resetting a testcase to re-run on a lab machine) just wouldn’t work on a Russian OS. Fortunately, the call stack was easy to investigate: (sorry it’s in Russian - globalization, what can you do…)

System.InvalidCastException: Приведение строки "2.0" к типу "Double" является недопустимым. ---> System.FormatException: Входная строка имела неверный формат.
в Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String Value, NumberFormatInfo NumberFormat)
в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
--- Конец трассировки внутреннего стека исключений ---
в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
в Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value)
в XXXXXXXX.Utilities.DotNetFramework.IsDotNetFramework35HigherInstalled()
в XXXXXXXX.Result.BulkResetResultsHelper(...

This essentially says: cannot convert a string “2.0” to double. Here’s the problem line of code (VB):

version = CDbl(numbers(0) & "." & numbers(1))

and here’s a fix:

version = System.Double.Parse(numbers(0) & "." & numbers(1), System.Globalization.CultureInfo.InvariantCulture)

The original code made an incorrect assumption that the decimal separator in the current culture is the ‘.’ character. However on German, Russian, Italian and some other OSs the default decimal separator is a ‘,’, not a ‘.’. By default, string operations use the current locale (and hence expect a comma as a decimal separator), so if you want to compose a string using a dot and convert it to a double, you have to use InvariantCulture, which uses a dot.

I’ve seen this error quite a lot of times – this is probably the most common globalization bug out there. Keep in mind, it’s 21st century out there, it’s likely that your software will be used all over the world on all possible combinations of operating systems, languages, locales, encodings, RTL etc.

A good read on this topic would be Jeffrey Richter’s CLR via C#, chapter 11 (Chars, Strings, and Working with Text), pages 264-268).