プリントデバッグ・サバイバルガイド
System.Diagnostics
名前空間の Debug
クラスや Trace
クラスを使ったプ
リント・デバッグを行う際に予め知っておくべきことについて書きます。
何故プリント・デバッグなのか
他の人が書いたテストも無く、仕様通りに動いているかどうか*1疑わしいコードに遭遇したことはありませんか?
それを解析もしくはデバッグ、あるいは機能追加する時、何から手をつけていけばいいでしょうか?
また、ステップ実行中には息を潜めているバグが存在しているというのは可能性として十分にありえます。
ここで登場するのが、プリント・デバッグです。
プリント・デバッグというのは、プリント・デバッグ用のコードを注意深く埋め込むことで実行中に何らかのデバッグ用の出力を吐くようにして、バグをとらまえようという試みです。
実際にやってみよう
まずは、Trace
クラスや Debug
クラスの Listeners
プロパティにリスナーを追加する必要があります。
app.config
にこんな感じに書いてみてください:
<configuration> <system.diagnostics> <trace autoflush="true" indentSize="4"> <listeners> <add name="hoge" type="System.Diagnostics.TextWriterTraceListener" initializeData="execution.log" /> </listeners> </trace> </system.diagnostics> </configuration>
これで Trace
クラスの Listeners
プロパティに TextWriterTraceListener
クラスのインスタンスが追加されます。
あと、Debug
クラスにも同じことが起こります。
下記は私がよくやる書き方の 1 つです:
void PerformHoge(string parameter) { Debug.Print( " ---> {0}#{1}", this.GetType().Name, MethodBase.GetCurrentMehod().Name ); Debug.Indent(); Debug.WriteLine( parameter, "parameter" ); Debug.Unindent(); Debug.Print( " <--- {0}#{1}", this.GetType().Name, MethodBase.GetCurrentMehod().Name ); }
主要なメソッドにこんな風に書いておくと、とても捗ることがあるかもしれません。
上記のメソッド PerformHoge()
を実行すると、こんな感じのログが出力されるはずです:
---> Hoge#PerformHoge
parameter: Hello, World!
<--- Hoge#PerformHoge
でも、こんな風に出力すると何が嬉しいんでしょう?
実はメソッドの呼びだされ方がインデントでよく見える様になります。
Indent()
と Unindent()
という 2 つの静的メソッドは、以降に出力されるログのインデントレベルを変更します。
つまり、Indent()
はインデントレベルを一段階上げ、Unindent()
はその逆のことを行います。
メソッド内のローカル変数やインスタンス変数の値を見たい時というのもあります。
こんな時、私はこうやっています:
Debug.WriteLine( hoge, "hoge" );
これはこんな感じの出力になります:
hoge: Hello, World!
Debug
や Trace
の WriteLine()
は少々独特です。
この場合の第二引数は何をやっているのでしょう?
第二引数の仮引数名は category
と云って実際の値の前の方にコロンを伴って出力されます。
Console
の WriteLine()
と同じシグネチャは存在しますが、引数を 2 つ渡している場合で第二引数が文字列型だった場合、意図したようにはなりません。
この場合のことを考えて、私は string.Format()
を使っています。
ここが Debug
や Trace
で厭なところです。
Debug.WriteLine( "Hello, {0}!", "World" ); // => World: Hello, {0}!
ではなく、
Debug.WriteLine( string.Format( "Hello, {0}!", "World" ) ); // => Hello, World!
という風に書きましょう。もしくは Print()
を使います:
Debug.Print( "Hello, {0}!", "World" ); // => Hello, World!
おしまい。