Visual Studioのイミディエイトウィンドウを使ってデバッグする

2019年11月14日

個人的によく使うシーンで、ブレークポイントで止めた状態で、クラスの中身をすべて表示させたい時とかに使う。
後で書くけど、うまくいかないプロジェクトとかもある。
何かしらusingして使わないといけないんだろうけど、これだ!というものがわからない。
誰か教えてください。

値を変更する

デバッグでイミディエイトウィンドウを使うシーンでよく使うのは値の変更だろう。引き続きさきほどのtempを例にすると

temp = "henkou"

これでよい。

値の確認

変数の中身が階層構造になってないパターン

数の値が知りたいとかの場合であれば、ブレークポイントで止めて、その変数名にカーソルを合わせたら見れる。
ただ、あえてイミディエイトウィンドウを使いたいことがあるかもしれない。
例えば、string temp = "aiueo" というのがあるとして、tempの中身がどうなってるか知りたいよという場合は、イミディエイトウィンドウで以下のようにする。

?temp
"aiueo"←こんな感じに出力される

変数の中身が配列等の階層構造になっている場合に中身を列挙する

普通にVisual Studio上で見る場合だと、クイックウォッチで見たり、ウォッチに入れたりする。
中身が知りたい場合だと、例えばListで格納されている場合、レコードごとにまとめられているので、わざわざクリックして展開してを繰り返さないといけない。
このような場合に、イミディエイトウィンドウは威力を発揮する。
例えば、以下のようなStudentクラスのリストがあったとする。

using System.Diagnostics;
using System.Collections.Generic;

namespace MyTest
{
    internal class Program
    {
        public class Student
        {
            public int ID { get; set; }
            public string LastName { get; set; }
            public string FirstMidName { get; set; }

            public Student(int id, string lastName, string firstMidName)
            {
                this.ID = id;
                this.LastName = lastName;
                this.FirstMidName = firstMidName;
            }
        }
        private static void Main(string[] args)
        {
            List<Student> students = new List<Student>();
            for (int i = 0; i < 5; i++)
            {
                students.Add(new Student(i,$"LastName{i}", $"FirstMidName{i}"));
            }
            Debug.WriteLine("");
        }
    }
}

中身をExcelとかに貼り付けてデータの確認なり、解析なりしたいことがあると思う。
そのような場合は、以下のようなコードをイミディエイトウィンドウで実行してやればよい。

ただし、 階層構造 を表示させたい場合にうまくいかないプロジェクトもある

Debug.Print(str)で以下のエラーが出る時がある。

error CS0234: 型または名前空間の名前 'Debug' が名前空間 'System.Diagnostics' に存在しません (アセンブリ参照があることを確認してください)。

これは、イミディエイトウィンドウが現在のプロジェクトをビルドして使用しており、System.Diagnosticsがビルドモジュールに含まれていないために発生している。

イミディエイトウィンドウは現在選択されているファイル/プロジェクトに依存
https://docs.microsoft.com/ja-jp/visualstudio/ide/reference/immediate-window?view=vs-2019

これを回避するために、上記コードにある
using System.Diagnostics;

Debug.WriteLine(“”);
をソースコード上に仕込んでいる。
using System.Diagnostics;だけだと、ビルド時に最適化されて使われていないと判定されて、含まれなくなってしまう。

しかし、不思議なことに、直接?を使えば、変数のみの場合見ることができる。

こんなエラーも。foreachの中でDebug.Printを使うとエラーが出る

以下のエラーが出てうまくいかないプロジェクトもある。

System.Collections.Generic.List`1[MyTest.Program+Student].ForEach(System.Action`1<MyTest.exe!MyTest.Program+Student>) で呼び出されるネイティブ メソッド System.Diagnostics.Debugger.IsLogging() を評価しています。このコンテキストでネイティブ メソッドを評価することはできません。

この解決策がまだわからない。恐らくこれも何かしら参照を追加してやらないといけないのかも。イミディエイトウィンドウにちゃんと吐き出されるパターンと吐き出されないパターンの違いがまだ判明していない。。。

代替策として、Debug.WriteLineで乗り切ることもある

なんかうまくイミディエイトウィンドウに出力されてないなーって時に
もうあきらめてソースコード直接いじってDebug.WriteLineで出力画面に表示させちゃうこともある。

            foreach (var student in students)
            {
                Debug.WriteLine($"ID:{student.ID} LastName:{student.LastName} FirstMidName:{student.FirstMidName}");
            }

ここでも出力ウィンドウに何もでないということがある。
この場合、以下の一行を追加してやる。
なんかしらんけど、トレースリスナのコレクションからDefaultTraceLisstenerが吹っ飛んでることがあるらしい。

Trace.Listeners.Add(new DefaultTraceListener());

出力ウィンドウではなく、イミディエイトウィンドウに出力させたい場合には、
ツール→オプション→デバッグ→全般
出力ウィンドウの文字をすべてイミディエイトウィンドウにリダイレクトする
にチェックする。

メモ

イミディエイトウィンドウに出力内容が多くなってきたら、イミディエイトウィンドウ上で右クリックしてクリアできる。

まとめ

ソースコードいじってどうこうというところまで話して思ったけど、もう普通にTextFileとかにストリームで吐くのがええやんということを思ってしまった。
まあ、それはそれ、これはこれということでね。
いけるときもあるので、そうした場合は時間短縮にもなるしね。うん。そう思うことにする。

テキストに吐き出すためのUtilでもつくっとこう。。