2017によるアプリのデバッグ方法デバッグの基本は、問題となっている可能性の高い箇所のコードを1ステップ(=1文)ずつ追跡して調べていくことである。それを行うには、怪しいと思われる箇所の一歩手前でプログラムの実行を一時的に停止させる必要がある。このプログラムの実行を一時停止する機能を「ブレークポイント」と呼ぶ。このデバッグ方法は、例えていうならば、DVDビデオを一時停止して(=ブレークポイント)、そこからコマ送りで再生する(=1ステップずつ追って調べる)という操作に似ている。今回のプログラムで問題となっている可能性の高いコードは、先ほど追加したフェードアウトのコードだ(なぜなら、フェードアウトを行う前は問題なく動作していたからだ)。そこで、menuItemClose_Clickメソッドの中にあるFormFadeOutメソッドにブレークポイントを仕掛けてみることにしよう。次の画面は、実際にブレークポイントを設定しているところだ。ブレークポイントの設定menuItemClose_Clickメソッドの中にあるFormFadeOutメソッドにブレークポイントを設定したところ。ブレークポイントを設定するには、該当行にカーソルを移動し、[F9]キーを押すだけである(もしくは左端の赤い●の部分をクリックしてもよい)。逆に、ブレークポイントを解除する場合も[F9]キーを押せばよい。複数箇所に設定したブレークポイントを一括解除したい場合には、[Ctrl]+[Shift]+[F9]キーを押せばよい。[ブレークポイントを無効にする]ボタン。これら2つのボタンについては後述する。ブレークポイントを設定したら、[F5]キーを押すか、メニューバーから[デバッグ]−[デバッグ開始]をクリックして、デバッグ実行を開始する。デバッグが開始されると「時計」アプリが起動するので、右クリックでコンテキストメニューを表示して[終了]を実行してみよう。すると、次の画面のようにブレークポイントを設定した位置で処理が停止するはずだ。ブレークポイントの位置で処理が停止した画面ブレークポイントを設定したFormFadeOutメソッドの呼び出し位置で処理が停止したところ。停止している箇所は黄色の矢印で示されている。IDEの右上には「診断ツール」が表示されている(後述)。処理を1ステップ(=1文)進めるには、[F10]キーを押す(「ステップオーバー」と呼ばれる)。メソッド内の処理に入るには、[F11]キーを押す(「ステップイン」と呼ばれる)。ここでは、FormFadeOutメソッド内部の処理を調べたいので、ステップインの[F11]キーを押す。すると、次の画面のように、FormFadeOutメソッドの内部に移って処理が停止する。ステップインしたメソッド内で処理が停止した画面[F11]キーを押して、FormFadeOutメソッド内部に入って処理が停止したところ。FormFadeOutメソッドの実装開始部分(「{」の場所)で処理が停止している。停止している箇所は黄色の矢印で示されている。「{」の右隣に「≦4ミリ秒経過」とあるのは、ステップ実行により、この行に制御が移るまでの経過時間。[呼び出し履歴]ウィンドウ(「コールスタック」とも呼ばれる)。[呼び出し履歴]ウィンドウを表示するには、メニューバーから[デバッグ]−[ウィンドウ]−[呼び出し履歴]を選択すればよい。このウィンドウでは、現在の処理がどういう順番で呼び出されたのかが分かる。直近に呼び出されたメソッドが最上位に、そのメソッドを呼び出したメソッドがその下に......という順序で、呼び出しのスタート地点が一番下に表示される。この画面では、最初に「MyClock.exeのMyClock名前空間のProgramクラスのMainメソッド」が呼ばれ(一番下)、その次に「DisplayクラスのmenuItemClose_Clickメソッド」が呼ばれ(上から2つ目)、最後に「FormFadeOutメソッド」が呼ばれている(一番上)ことが分かる。この画面の例は単純だが、メソッドの呼び出しが複雑な場合、この[呼び出し履歴]ウィンドウが役立つことがある。[呼び出し履歴]ウィンドウ内のメソッドをダブルクリックすれば、そのメソッド呼び出しの該当行にジャンプできる。Frameworkが提供するコードのことだ。どんなメソッドが実際に呼び出されているかは[呼び出し履歴]ウィンドウを右クリックしてコンテキストメニューから[外部コードの表示]を選択すればよい。Frameworkが提供するコードが深く絡み合って実行されていることがよく分かるだろう。次に[F10]キーでステップオーバーして、FormFadeOutメソッドの処理を1ステップずつ進めていってみよう。すると、forループの間をぐるぐると繰り返し実行しているのが分かるだろう。ここで、forループ内にある、変数「n」の値やOpacityプロパティの値がバグの原因として疑わしいので、どうなっているか調べてみよう。これを調べるには、次の画面のように[ウォッチ]ウィンドウを使う。[ウォッチ]ウィンドウによる変数状態の確認[ウォッチ]ウィンドウで変数の状態を確認しているところ。1]を選択すればよい。[ウォッチ]ウィンドウで調べたい変数やプロパティ、メソッドなどを選択して(ダブルクリックで単語を選択できる)、[ウォッチ]ウィンドウ内にドラッグ&ドロップする。[ウォッチ]ウィンドウに追加された変数やプロパティの値は、処理を1ステップ進めるごとにリアルタイムに更新される。変数やプロパティの上にマウスカーソルを乗せることで、その変数やプロパティの状態をツールチップで表示できる。[ウォッチ]ウィンドウでOpacityプロパティあるいは変数「n」の値を参照すると、「49」から減るはずの値が「51」と逆に増えている。forループのコードで、カウントアップ(=インクリメント)していたのが間違っていたということだ(「n++」は1ずつカウントアップするという意味)。n++)forループでカウントアップする間違ったコード正しくは、次のようにカウントダウン(=デクリメント)しなければならなかったわけだ(「n--」は1ずつカウントダウンするという意味)。n--)forループでカウントダウンする正しいコードこのコーディングミスにより、プログラムは無限に(厳密には数値の範囲があるので有限だが......)カウントアップし続け、アプリがフリーズした(「応答なし」の)状態になっていたわけだ。バグの箇所が判明したので、[Shift]+[F5]キーを押すか、メニューバーから[デバッグ]−[デバッグの停止]を選択するかして、デバッグ実行を終了する。先ほどのforループのコードの誤りを修正して、再ビルドを行い、もう一度デバッグ実行をしてみよう。フォームを右クリックしてコンテキストメニューから[終了]を選択し、FormFadeOutメソッドで実行が止まったら、先ほどと同様な手順でステップ実行を行い、フォームのOpacityプロパティ(this.Opacity)の値が減っていることを[ウォッチ]ウィンドウで確認する。確認ができたら、全体の動作についても確認しておこう。これには[F5]キーを押すかメニューバーから[デバッグ]−[続行]を選択すればよい。すると、次は正常にフェードアウトしながら、アプリが終了するはずだ。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。