覚えておきたい DebuggerDisplay
皆もうとっくに知ってるかもしれませんが、最近 DebuggerDisplay 属性というのを覚えました。
https://msdn.microsoft.com/ja-jp/library/x810d419.aspx
こいつがなかなかに良いやつだったので、ちょっと調べた結果をメモっておきます。
目的と基本的な使い方
DebuggerDisplay 属性は、Visual Studio でのデバッグ時にインスタンスの値を表示するのに使います。まぁ例を見た方が早いです。
class Program { static void Main(string[] args) { var obj = new Employee { Id = 1, Name = "太郎" }; Console.WriteLine(obj); } } [DebuggerDisplay("Id={Id}, Name={Name,nq}")] public class Employee { public int Id { get; set; } public string Name { get; set; } }
このコードの Console.WriteLine(obj);
にブレークポイントを張って、Visual Studio でデバッグ実行します。
ブレークしたら、[デバッグ] > [ウインドウ] > [ローカル] でローカル変数のキャプチャを見てみると、、、
この通り、 DebuggerDisplay に設定した値が参照できます。
メソッド呼び出しも出来る
先ほど DebuggerDisplay に設定したのはクラスのプロパティでした。
へーじゃあもしかしてメソッドも呼びだしとかも出来るの?という疑問も出てくるかと思いますが、出来ます。
class Program { static void Main(string[] args) { var obj = new Employee { Id = 1, Name = "太郎" }; Console.WriteLine(obj); } } [DebuggerDisplay("{Debug()}")] public class Employee { public int Id { get; set; } public string Name { get; set; } public string Debug() { return "called Debug()"; } }
夢が広がりますね。
static だって private だって見えちゃう
で、プロパティも見えます、メソッドも呼べますときたら今後は可視性です。どこまで見えるか?全部見えます。
class Program { static void Main(string[] args) { var obj = new Employee { Id = 1, Name = "太郎" }; Console.WriteLine(obj); } } [DebuggerDisplay("{PrivateStaticDebug()}")] public class Employee { public int Id { get; set; } public string Name { get; set; } private static string PrivateStaticDebug() { return "called PrivateStaticDebug()"; } }
この通り。
DebuggerDisplay 属性が付いてないクラスも見えたりするの?します。
class Program { static void Main(string[] args) { var obj = new Employee(); Console.WriteLine(obj); } } [DebuggerDisplay("{PrivateStaticDebug()}")] public class Employee { private PrivateClass _field = new PrivateClass(); } public class PrivateClass { private string _privateField = "private field"; }
やばいですね。やりたい放題です。
注意点
そんな便利な DebuggerDisplay 属性ですが、ちょっと注意点があります。
MSDN を読むと分かりますが、メソッド呼び出しは推奨されていません。なんでかというと、ステップ実行毎に呼び出されるためです。
class Program { static void Main(string[] args) { var obj = new Employee(); Console.WriteLine(obj); Console.WriteLine(obj); } } [DebuggerDisplay("{Debug()}")] public class Employee { private int count = 0; public string Debug() { return "called Debug() " + (++count); } }
↑のコードで最初の Console.WriteLine(obj);
時点では
なんですが、次のステップに進むと、、、
count
が上がりました。再度のメソッド呼び出しがかかってますね。
なので、あまり重いメソッドを呼び出したりすると、ステップ実行がしんどくなります。ただ、デバッグ実行したら常に呼び出されるか?例えば 100 ステップのコードであれば 100 回呼び出されるかというとそうではなくて、ステップ実行しなければ大丈夫です。
まとめ
知っている人も多いかと思いますが、デバッグ実行時に表示される値は ToString()
をオーバーライドしている場合その呼び出し結果が使われます。なので、 DebuggerDisplay 属性をそんな使うかというと、実際使わないですね。
ただ、ToString()
では困るケースというのが全くない訳でもなくて、例えば ToString()
は別にデバッグ用ではないので、デバッグには足りない実装が既にされていたりします。あるいは、private も参照できるということで、そういう特殊な状況において輝いてくる機能かなと思います。なので、普段使いとはいかなくとも覚えておいて損はないかと。