ウォッチウィンドウってすばらしい!
ウォッチウィンドウっていいですよね!(゚∀゚)
自作のクラスでも適切な設定をしておけば、デバッグ時に分かりやすく表示してくれますよ。
アプリケーション固有の業務クラスを書いているときには、そこまで手間掛けてもなぁ・・・って思うかもしれないけど、ライブラリクラスなら長い間お世話になるので一手間掛ける価値ありですよ。
以下は家族構成を表すクラスの適当なサンプルです。
public enum SEX
{
Male,
Femail,
Ahhhhh,
}
public class Person
{
private Family Family;
public string FirstName;
public int Age;
public SEX Sex;
public Person(Family family)
{
Family = family;
}
}
public class Family
{
public string FamilyName;
private List<Person> _members = new List<Person>();
public IEnumerable<Person> Members { get { return _members; } }
public Person AddMember(string firstName, int age, SEX sex)
{
var member = new Person(this)
{
FirstName = firstName,
Age = age,
Sex = sex,
};
_members.Add(member);
return member;
}
}
このクラスのインスタンスを作成するコードを書いてみます。
static void Main()
{
var abe = new Family() { FamilyName = "阿部" };
abe.AddMember("太郎", 25, SEX.Male);
abe.AddMember("花子", 22, SEX.Femail);
abe.AddMember("高和", 28, SEX.Ahhhhh);
}
それでは実行してウォッチで abe を見てみましょう。
それなりに便利ではありますけど、値のところにクラス名がズラズラ並んでいるのが嫌になりませんか?
私は嫌です(`・ω・´)
Family クラスをもっと見やすくしよう
そこでFamilyクラスに DebuggerDisplay 属性を設定します。
using System.Diagnostics;
[DebuggerDisplay("{FamilyName}({_members.Count})")]
public class Family
{
// 略
}
このようにプロパティ名を { } でくくると内容を展開して表示してくれます。
ほかにも ToString メソッドをオーバーライドする方法もありますが、ToString はデバッグ目的ではなくインスタンスを文字列表現したものを返すためなので、ウォッチ用の文字列出力に用いるのはふさわしくないと思っています。
DataGridView に投げたら ToString の内容がユーザーにまで表示されますしね。
もっと複雑な文字列組み立てが必要な場合は、デバッグ専用のプロパティを実装して、それを DebuggerDisplay に渡すのがベストだと思います。
Personクラスも同じように、デバッグに役立つ情報を入れてあげましょう。
かなりすっきりしましたね!
不要なメンバーは隠しちゃおう
Family クラスの _members と Members が表示されていますが、Members は _members をただ返しているだけなので両方見られてもメリットがなさそうです。
そこで、ウォッチに表示したくないメンバーに DebuggerBrowsable 属性をつけて非表示にします。
[DebuggerDisplay("{FamilyName}({_members.Count})")]
public class Family
{
public string FamilyName;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private List<Person> _members = new List<Person>();
// 略
}
ん?? スクリーンショットにマウスポインターが映ってる・・・ orz
で、でも、かなりすっきりしましたよね!( ̄▽ ̄;)
もし DebuggerDisplay 用のプロパティを実装している場合は、それにも DebuggerBrowsable 属性を当てて非表示にしちゃいましょう。
ウォッチ用にプロパティ追加するとクラスが汚れる
もっと積極的にカスタマイズするなら DebuggerTypeProxy がありますよ。
これはウォッチで表示するときに指定したラッパークラスを表示することで、よりダイナミックに表示をカスタマイズするための仕組みです。
デバッグ表示を別のクラスに分離できるので、大きなクラスの場合はすっきりしていいかもしれません。
public class DebuggerFamilyProxy
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Family _family;
public DebuggerFamilyProxy(Family family)
: base()
{
_family = family;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public IEnumerable<Person> Members { get { return _family.Members; } }
}
ラップするクラスのインスタンスを受け取れる引数を持つコンストラクタを定義します。
あとはそのインスタンスをどのようにウォッチで見せたいかによって、プロパティを定義していくだけです。
ここでは Members のみを実装し、DebuggerBrowsable 属性でルートを省略するように指定してみました。
ラッパークラスが完成したら、Family クラスに DebuggerTypeProxy 属性を付けてラッパークラスの型情報を渡せば完成です。
[DebuggerTypeProxy(typeof(DebuggerFamilyProxy))]
[DebuggerDisplay("{FamilyName}({_members.Count})")]
public class Family
{
//略
}
Members のルートを省略したので、いきなり Family が展開された状態で見ることが出来ます。便利かどうかは疑問ですけどw
下に2つ連続している列ビューは上が Members のもので、下が Family です。
まとめ
Debugger 属性を積極的に活用して快適な C# ライフを送りましょう♪
ちなみにデザイナ画面でよく使うプロパティグリッドは、クラスの内容をウォッチのように見ることが出来ますよね。
DebuggerTypeProxy のような思い切ったカスタマイズする場合は TypeConverter 属性を使います。
でもこっちは実装が、ややこしくて難しかったです・・・。
ネットにも情報がほとんど無いしプロパティグリッドは触らない方がいいですね(;´д`)