DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

デバッガ変数ウィンドウに表示される内容を変更する

デバッグ中にVisual Studioのコードエディタで変数の上にマウスポインタを移動させると、ツールチップが表示されます。また、デバッガ変数ウィンドウにも変数の情報が表示されます。これらに表示される内容を変更する方法について、ここでは説明します。

値、名前、型の表示を変更する

例えば、以下の様なクラスがあったとします。

VB.NET
コードを隠すコードを選択
Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property
End Class
C#
コードを隠すコードを選択
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }
}

このクラスを使用した以下の様なコードを書き、2行目にブレークポイントを挿入して、デバッグを開始してみます。

VB.NET
コードを隠すコードを選択
Dim c As New SampleClass()
'↓の行にブレークポイントがあるものとする
Console.WriteLine(c.ToString())
C#
コードを隠すコードを選択
SampleClass c = new SampleClass();
//↓の行にブレークポイントがあるものとする
Console.WriteLine(c.ToString());

ブレークポイントで中断中に変数「c」にマウスポインタを置くと、次のようなツールチップ(「c|{SampleClass}」)が表示されます。(ここで紹介している画像はすべてVisual Studio 2010のC#での結果です。)

c|{SampleClass}

ここに表示される文字列はToStringメソッドの結果ですので、もし変更したければToStringをオーバーライドします。

例えば以下のようにToStringをオーバーライドしたとします。

VB.NET
コードを隠すコードを選択
Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property

    'ToStringメソッドをオーバーライドする
    Public Overrides Function ToString() As String
        Return String.Format("{0} | {1}", Me.Words.Length, Me.Message)
    End Function
End Class
C#
コードを隠すコードを選択
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }

    //ToStringメソッドをオーバーライドする
    public override string ToString()
    {
        return string.Format("{0} | {1}", this.Words.Length, this.Message);
    }
}

するとツールチップは次のように表示されるようになります。

c|{3 | こんにちは。}

しかしToStringをオーバーライドしなくても、DebuggerDisplayAttributeを使用すればこの表示内容を変えることができます。この属性は、.NET Framework 2.0以降で使用できます。

以下にその使用例を示します。

VB.NET
コードを隠すコードを選択
'Imports System.Diagnostics

'DebuggerDisplay属性を適用して、デバッガ変数ウィンドウの表示内容を変える
<DebuggerDisplay("{Words.Length} | {Message}")> _
Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property
End Class
C#
コードを隠すコードを選択
//using System.Diagnostics;

//DebuggerDisplay属性を適用して、デバッガ変数ウィンドウの表示内容を変える
[DebuggerDisplay("{Words.Length} | {Message}")]
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }
}

このようにすると、ツールチップは以下のように表示されるようになります。ToStringの時と違い、全体が { } で囲まれなくなり、逆に文字列は " " で囲まれます。

c|3 | "こんにちは。"

「{Words.Length}」と「{Message}」は、この箇所にWordsのLengthプロパティとMessageプロパティを表示することを意味します。この { } 内には、フィールド、プロパティ、メソッドの名前を記述できます。また、{ } 内に簡単な式を記述することもできます。

ツールチップの表示だけでなく、デバッガ変数ウィンドウの表示も変化しています。何もしていないSampleClassは、デバッガ変数ウィンドウでは次のように表示されます。なおデバッガ変数ウィンドウを表示するには、デバッグ中にVisual Studioのメニューで[デバッグ]-[ウィンドウ]-[自動変数]などを選択してください。

デバッガ変数ウィンドウ

SampleClassにDebuggerDisplay属性を適用すると、以下のように「値」が変化します。

デバッガ変数ウィンドウ

さらにDebuggerDisplay属性で、デバッガ変数ウィンドウの「名前」と「型」を変更することもできます。以下の例では、値にWordsのLengthプロパティ、名前にMessageプロパティ、型に「サンプル」と表示されるようにしています。

VB.NET
コードを隠すコードを選択
'Imports System.Diagnostics

<DebuggerDisplay("{Words.Length}", Name := "{Message}", Type := "サンプル")> _
Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property
End Class
C#
コードを隠すコードを選択
//using System.Diagnostics;

[DebuggerDisplay("{Words.Length}", Name = "{Message}", Type = "サンプル")]
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }
}

このようにすると、デバッガ変数ウィンドウには以下のように表示されるようになります。以下の画像はC#でのもので、名前は変更されませんでした。しかしVB.NETでは名前も変更されました。

デバッガ変数ウィンドウ

補足:DebuggerDisplay属性は、クラス以外に、構造体、デリゲート、列挙体、フィールド、プロパティ、アセンブリに適用できます。

メンバの表示を変更する

ツールチップやデバッガ変数ウィンドウでは、変数名の左に表示される「+」をクリックすることで、そのオブジェクトのメンバの情報を表示させることができます。

例えば、何もしていないSampleClassクラスでは、次のように表示されます。

ツールチップ

デバッガ変数ウィンドウ

表示しないメンバを指定する

DebuggerBrowsableAttributeを使うと、デバッガ変数ウィンドウに表示しないメンバを指定することができます。この属性は、.NET Framework 2.0以降で使用できます。また、.NET Framework 2.0のVB.NETではサポートされていません。

SampleClassクラスでプライベートフィールドをデバッガ変数ウィンドウに表示しないようにした例を以下に示します。

VB.NET
コードを隠すコードを選択
'Imports System.Diagnostics

Class SampleClass
    'デバッガウィンドウに表示しない
    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    'デバッガウィンドウに表示しない
    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _
    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property
End Class
C#
コードを隠すコードを選択
//using System.Diagnostics;

class SampleClass
{
    //デバッガウィンドウに表示しない
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    //デバッガウィンドウに表示しない
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }
}

ツールチップ

配列やコレクションのルートを表示しない

DebuggerBrowsable属性を使用して、配列やコレクションのルートを表示しないようにすることもできます。

SampleClassクラスを以下のように書き換えたとします。

VB.NET
コードを隠すコードを選択
'Imports System.Diagnostics

Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    '配列のルート要素を表示しない
    <DebuggerBrowsable(DebuggerBrowsableState.RootHidden)> _
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property
End Class
C#
コードを隠すコードを選択
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    //配列のルート要素を表示しない
    [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
    public string[] Words
    {
        get { return this._words; }
    }
}

すると以下のように「Words | {string[3]}」という項目がなくなり、Wordsプロパティの要素があたかもSampleClassの要素のように表示されます。よってこの属性はインデクサに使われることが多いです。

ツールチップ

代わりに別の型のメンバを表示する

DebuggerTypeProxyAttributeを使えば、全く別のクラス(型の表示プロキシ)のメンバをあたかもそのクラスのメンバのように、デバッガ変数ウィンドウに表示することができます。これを使えば、かなり柔軟にメンバの表示内容を変更することができます。この属性も、.NET Framework 2.0以降で使用できます。

以下の例では、表示プロキシとしてSampleClassDebugViewクラスを作成して、Messageプロパティはそのまま表示し、Wordsプロパティはコンマ区切りで表示されるようにしています。

VB.NET
コードを隠すコードを選択
'Imports System.Diagnostics

'型の表示プロキシにSampleClassDebugViewを指定する
<DebuggerTypeProxy(GetType(SampleClass.SampleClassDebugView))> _
Class SampleClass
    Private _message As String = "こんにちは。"
    Public Property Message() As String
        Get
            Return Me._message
        End Get
        Set(ByVal value As String)
            Me._message = value
        End Set
    End Property

    Private _words As String() = New String() {"壱", "弐", "参"}
    Public ReadOnly Property Words() As String()
        Get
            Return Me._words
        End Get
    End Property

    '表示プロキシ
    Friend Class SampleClassDebugView
        'プロキシを使用するオブジェクトを取得する
        Private _sampleClass As SampleClass
        Public Sub New(ByVal sc As SampleClass)
            Me._sampleClass = sc
        End Sub

        'Messageプロパティはそのまま表示する
        Public ReadOnly Property Message() As String
            Get
                Return Me._sampleClass.Message
            End Get
        End Property

        'Wordsプロパティはコンマ区切りで表示する
        Public ReadOnly Property Words() As String
            Get
                Return String.Join(",", Me._sampleClass.Words)
            End Get
        End Property
    End Class
End Class
C#
コードを隠すコードを選択
//using System.Diagnostics;

//型の表示プロキシにSampleClassDebugViewを指定する
[DebuggerTypeProxy(typeof(SampleClassDebugView))]
class SampleClass
{
    private string _message = "こんにちは。";
    public string Message
    {
        get { return this._message; }
        set { this._message = value; }
    }

    private string[] _words = new string[] { "壱", "弐", "参" };
    public string[] Words
    {
        get { return this._words; }
    }

    //表示プロキシ
    internal class SampleClassDebugView
    {
        //プロキシを使用するオブジェクトを取得する
        private SampleClass _sampleClass;
        public SampleClassDebugView(SampleClass sc)
        {
            this._sampleClass = sc;
        }

        //Messageプロパティはそのまま表示する
        public string Message
        {
            get { return this._sampleClass.Message; }
        }

        //Wordsプロパティはコンマ区切りで表示する
        public string Words
        {
            get
            {
                return string.Join(",", this._sampleClass.Words);
            }
        }
    }
}

このように変更すると、ツールチップは以下のように表示されるようになります。

ツールチップ

上の画像はC#でのもので、VB.NETでは異なります。C#では表示プロキシのパブリックメンバしか表示されませんが、VB.NETではプライベートメンバも表示されます。またC#では「列ビュー」という項目で基のオブジェクトのメンバが表示されますが、VB.NETではこの項目が表示されません。

補足:DebuggerTypeProxy属性は、クラス以外に、構造体、アセンブリに適用できます。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。