[.NET] 特定ロケールのみで発生する例外の不思議


はじめに

ポーランドの友から、謹製ソフトウェアが処理途中でクラッシュするという報告を受けた。
しかしながら、自分の環境では一向に問題が再現しない。
原因を探っていくとなかなか面白い問題であったので、本記事で共有する。

例外が発生するコード

例外を再現できる最低限のコードが、下記である。
このコードは、日本や中国、アメリカなど多くの端末で成功するが、一部地域の端末では例外を吐く。

C#
var num = float.Parse("0.25");

なぜか?

一部の地域では、小数点を . ではなく , で表現する。(e.g. 0,25)
したがって、0.25 という文字列はfloatとしてパースできず、FormatException を発生してしまう。

解決法

Parse メソッドの第二引数には、 IFormatProvider として CultureInfo インスタンスを渡すことができる。
この引数がない場合、プログラムが実行されている端末のロケールがデフォルトで利用されるようだ。
これでは環境依存のバグにつながる。

問題を回避するため、この引数に適切なロケールを渡してやれば良い。
多くの場合、CultureInfo.InvariantCulture が有効だろう。

IFormatProviderに渡す
float.Parse("0.25", CultureInfo.InvariantCulture);

あるいは、CurrentCulture を適切なロケールに書き換えてしまうのも有効と思われる。

CurrentCultureの書き換え
System.Globalization.CultureInfo.CurrentCulture = new CultureInfo("en-us");

シリアライズされたテキストを読み込むようなときは、上記のようにロケールを固定して問題ないだろう。

無理やり問題を再現させるには

Locale Emulator なるものがあるらしい。
これで再現環境でのロケールを設定すれば、自分の端末でも問題を容易に再現できるはずだ。
(しかしながら、今回のソフトウェアではエミュレータがうまく機能しなかった……)

終わりに

こういったバグはなかなか予見しづらいが、原因の存在を知っていることは重要である。
さすれば報告を受けたときに、迅速な対応が可能になるだろう。