初心者のためのC#プログラミング本格入門77 - 地味で目立たない努力が大量のバグを消す
早速ですが、再びサンプルプログラムのテストを実行してみましょう。まだ大量のエラーが表示されています。大量のエラーが表示されると初心者は慌てがちですが、心配する必要はありません。落ち着いて1行目のみ見てみましょう。そうすると、「-2147483648 + -2147483647」のテストそのものがおかしい事に気付くと思います。正しい値として表示されている値そのものがおかしいのです。テストそのものが間違っている場合も視野に入れてチェックしましょう。
このテストプログラムはどこが間違っているのでしょうか?前回の記事の内容を思い返して下さい。そうすれば答えが分かります。答えは「使用している型がおかしい」です。前回述べたように、float型では扱える値の範囲が不十分です。という事は、テストプログラムの方もdouble型にしておかないと正しい計算結果が得られません。修正しましょう。
//計算処理をチェックする
private void CalculateTest( double value1, double value2, char sign )
{
string inputValue = value1 + " " + sign + " " + value2;
this.target = new MultiAnalyzer();
this.target.AnalyzeExpression( inputValue );
double result = target.Calculation();
double rightValue = 0;
//あとは省略...
}
再び実行して、1行目のエラー文を見て下さい。正しい値になっている事が分かります。テストを修正した後は、テスト対象を修正します。1行目のエラー文の処理結果をみると、正しい値との差が激しい事が分かります。次に値に注目するとたった1です。1という数値がどうして算出されたのか考えると、-2147483648と-2147483647の差である事に気付くと思います。という事は、加算演算をするべき場面で減算演算をしていると推測できます。推測したら検証します。
class AnalyzerTest
{
//他のコードは省略...]
public void ExecuteAllTest()
{
this.MinusValueCheck();
this.MinusValueLimitCheck();
this.MinusExpressionSignCheck();
}
//符号が正しく取得できているかチェック
public void MinusExpressionSignCheck()
{
string value = int.MinValue +
" + " + int.MinValue;
this.target = new Analyzer();
this.target.AnalyzeExpression( value );
if ( this.target.Sign != '+' )
{
System.Console.WriteLine(
"符号を正しく解析できませんでした。" +
"(正しい符号「+」, " +
"返された符号 " + this.target.Sign );
}
}
}
テストを実行すると、案の定符号が「-」になっています。このバグの原因を探りましょう。符号が正しく習得できていないという事は、式が正しく解析できていないことを意味します。これが分かれば、チェックするプログラムも自然と分かります。
public void AnalyzeExpression( string inputValue )
{
//数値を取り出す
string tmp = inputValue;
AddValues( ref tmp );
//符号を取り出す
System.Tuple<bool, char, string> signInfo = GetSign( tmp );
this.sign = signInfo.Item2;
//処理が成功しているか否かを記録
this.success = this.values.Count != 0 &
signInfo.Item1 == true;
}
処理の流れをよく見ると、数値を取り出す → 符号を取り出す → 成功の有無 となっています。処理の流れから、GetSignメソッドに渡される値は、数値が取り出された後に処理をすると想定されている事が分かります。この考えが正しいかデバッグ機能を使って確認してみましょう。先ずはMinusExpressionSignCheckメソッド内のコード「this.target.AnalyzeExpression( value );」にブレークポイントを設定します。設定したらデバッグ実行します。すると、設定したコードでストップしますから、AnalyzeExpressionメソッド内のコード「System.Tuple<bool, char, string> signInfo = GetSign( tmp );」にブレークポイントを設定します。その後、F5キーを押すと、そこまで処理が進んだ後にストップします。ローカル変数ウィンドウで、tmpの値を確認して下さい。そうすれば、GetSignメソッドに渡される値に数値を含んでいる事が分かります。確認できたらもう一度F5キーを押します。
以上のチェックで分かったのは、想定外の値がメソッドに渡されている事です。この値を正しくするには、直前の処理(AddValuesメソッド)で変数tmpの内容を変更せねばなりません。いまこぞ、新しい文法が必要です。この様に、メソッド内で渡された変数の内容を変更したい時はrefキーワードを使用します。
public void AddValues( ref string inputValues )
{
bool loopFlag = true;
string tmp = inputValues;
do
{
System.Tuple<bool, double, string> value =
TryValue( tmp );
loopFlag = value.Item1;
if ( loopFlag == true )
{
this.values.Add( value.Item2 );
tmp = value.Item3;
}
} while ( loopFlag == true );
inputValues = tmp; //結果を反映
}
public void AnalyzeExpression( string inputValue )
{
//数値を取り出す
string tmp = inputValue;
AddValues( ref tmp ); //呼び出し側もrefを書く
//符号を取り出す
System.Tuple<bool, char, string> signInfo = GetSign( tmp );
this.sign = signInfo.Item2;
//処理が成功しているか否かを記録
this.success = this.values.Count != 0 & signInfo.Item1 == true;
}
変更点を緑色で示しました。refキーワードは、パラメーターにつけるだけです。あとは、パラーメタ―に結果を反映すればOKです。最後の仕上げとして、デバッグ実行(F5)をして下さい。エラー文が大量に消えた事を確認できます。やったね♪今回の記事で示したように、ちょっとした事でエラーは消えます。それが、デバッグとテストの醍醐味です。テストとデバッグは地味で退屈な作業だと思われがちですが、面白さと大切さが分かれば見方は変わるでしょう。プログラミングでもそうなのですが、あらゆる物事は地味で目立たない行為に支えられています。その真理を見抜き、そこに喜びを見出すことこそ、プログラミング上達への道です。