はじめに
上級プログラマーの知識としては常識(忘れている場合も多々ある )ですが、初心プログラマにはよく陥る罠です。
この罠の知識があれば、この罠が原因で例外が発生しているのかなと想像つきます。
正直なところ、自分自身への戒めの意味もあります
たまに発生する例外
一般向けアプリを作成し、500名位に1名位の割合で、プログラム起動時、設定ファイル読み込み時に例外が発生します。開発環境で実証テストを行っても発生せず。「環境依存じゃないの?」とか「Windows Updateが当たってないんじゃないのか?」等とユーザーの環境に原因があるような事で済まされる可能性があります。
地域設定を確認せよ
その時、ユーザーのPCの地域設定パネルの形式を確認して下さい。「日本語(日本)」になってますか?
あるユーザさんは何故か「アイスランド語(アイスランド)」になってました。
形式がこの設定になっていると、小数点が「.」(ドット)でなく「,」(カンマ)になります。
カンの良い方ならピーンときますが、設定ファイルから読み込み処理を行う時に、小数点の解釈ができずに例外が発生するのです。
おいおいバグじゃん
コードは以下のようになってました
var stringValue = "2.54"; //ファイルから読み込んだと仮定する
var decimalValue = default(decimal);
decimal.TryParse(stringValue, out decimalValue);
上記のように簡単に文字列→数値変換を行うと、Parse() または **TryParse()で解釈する文字列は、地域設定のコントロールパネルの設定に影響されます。
初心者プログラマは気にせず上記のコードを作成しがちです。2つの引数でParse()**を呼び出すのは禁止にした方が良いかも知れません。
対策
地域設定の影響を受けないようにするためには、以下のように InvariantCulture を明示的に指定して、**Parse()**を行うべきです。
var stringValue = "2.54"; //ファイルから読み込んだと仮定する
var decimalValue = default(decimal);
decimal.TryParse(stringValue ,
NumberStyles.Number,
System.Globalization.CultureInfo.InvariantCulture,
out decimalValue );
コーディング規約に謳おう!
現場では、拡張メソッドにして、Parsr()やTryParse()は使用禁止を謳った方が良いと思います。
/// <summary>
/// 文字列→decimal
/// </summary>
/// <param name="stringValue">文字列</param>
/// <param name="defaultValue">失敗時の数値</param>
/// <returns>解析されたdecimal値</returns>
static public decimal ToDecimal(this string stringValue, decimal defaultValue = decimal.Zero)
{
var value = defaultValue;
if (decimal.TryParse(stringValue, NumberStyles.Number,
System.Globalization.CultureInfo.InvariantCulture, out value))
{
return value;
}
return defaultValue;
}