DebugTrace-net チュートリアル

DebugTraceについて

DebugTrace-javaチュートリアルを参照ください。

プロジェクト(C#)の作成

Visual Studio 2019(日本語サイト)を使用するのでインストールします。 Visual Studio 2019の言語が日本語の場合は、以下の内容を適宜日本語に置き換えてください。

  1. Visual Studio 2019を起動後にCreate a new projectをクリックします。(または[File]-[New]-[Project...]を実行)
  2. Create a new Projectダイアログが表示されるので、Class Libraey (.NET Core)を選択してNextをクリックします。
  3. Configure your new projectダイアログが表示されるので、以下を入力してCreateをクリックするとプロジェクトが作成されます。
    Project name: Tutorial
    Location: <任意>
    Solution name: DebugTraceNetTutorial
    ▢ Place solution and project in the same directory
  4. Solution ExplolerでTutorialプロジェクトのDependenciesのコンテキストメニュー(右ボタンでクリック)からManage Nuget Packeges...を選択します。
  5. 生成されたソース(DebugTraceNetTutorial/Tutorial/Class1.cs)を削除し、Tutorialプロジェクト下にsrcフォルダーを作成します。
  6. [File]-[New]-[Project...]を実行します。
  7. Create a new Projectダイアログが表示されるので、MSTest Test Project (.NET Core)を選択してNextをクリックします。
  8. Configure your new projectダイアログが表示されるので、以下を入力してCreateをクリックするとテストプロジェクトが追加されます。
    Project name: TutorialTest
    Location: <変更なし>
    Solution: Add to solution
    Solution Name: <入力不可>
  9. 生成されたソース(DebugTraceNetTutorial/TutorialTest/UnitTest1.cs)を削除し、TutorialTestプロジェクト下にsrcフォルダーを作成します。
  10. TutorialTest/DependenciesのコンテキストメニューからAdd Project Reference...を選択し、Tutorialプロジェクトにチェックを入れ[OK]をクリックします。

f:id:MasatoKokubo:20201123101039p:plain

チュートリアル1

Tutorial/src下に以下のソースファイルを追加します。
パス: DebugTraceNetTutorial\Tutorial\src\Tutorial1.cs

using System.Text;

namespace DebugTraceTutorial {
    public class Tutorial1 {
        public static int MaxLogByteArrayLength = 1024;

        /// <summary>
        /// バイト配列の文字列表現をStringBuilderに追加する。
        /// </summary>
        /// <param name="builder">StringBuilder</param>
        /// <param name="bytes">バイト配列</param>
        /// <returns>引数のbuilder</returns>
        public static StringBuilder AppendBytes(StringBuilder builder, byte[] bytes) {
            builder.Append('[');
            var delimiter = "";
            for (var index = 0; index < bytes.Length; ++index) {
                builder.Append(delimiter);
                if (index >= MaxLogByteArrayLength) {
                    builder.Append("...");
                    break;
                }
                var value = bytes[index];
                var ch = (char)(value / 16 + '0');
                if (ch >= '9') ch += (char)('A' - '9' - 1);
                builder.Append(ch);
                ch = (char)(value % 16 + '0');
                if (ch >= '9') ch += (char)('A' - '9' - 1);
                builder.Append(ch);
                delimiter = ", ";
            }
            builder.Append(']');
            return builder;
        }
    }
}

TutorialTest/src下に以下のソースファイルを追加します。
パス: DebugTraceNetTutorial\TutorialTest\src\Tutorial1Test.cs

using DebugTraceTutorial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text;

namespace DebugtraceTutorial {
    [TestClass]
    public class Tutorial1Test {
        /**
         * appendBytesのテスト。
         * @param bytes バイト配列
         * @param expected StringBuilderに追加されると期待する文字列
         */
        [DataTestMethod]
        [DataRow(new byte[] {}, "[]")]
        [DataRow(new byte[] {1}, "[01]")]
        [DataRow(
            new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
            "[00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F]"
        )]
        [DataRow(
            new byte[] {0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF},
            "[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, FA, FB, FC, FD, FE, FF]"
        )]
        public void TestAppendBytes(byte[] bytes, string expected) {
            // when
            var builder = Tutorial1.AppendBytes(new StringBuilder(), bytes);

            // then
            Assert.AreEqual(expected, builder.ToString());
        }
    }
}

テストを実行すると最初の2つの引数のテストは成功しますが、その後のテストでは失敗します。

テスト結果(最初の失敗):

Assert.AreEqual failed. Expected:<[00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F]>. Actual:<[00, 01, 02, 03, 04, 05, 06, 07, 08, 0@, 0A, 0B, 0C, 0D, 0E, 0F]>.

08, 0@, 0Aではなく08, 09, 0Aとなるのが正しいです。

DebugTrace-netを使用してみます。

プロジェクトにDebugTrace-netパッケージを以下の手順で追加します。 1. Solution ExplorerTutorial/DependeciesコンテキストメニューからManage NuGet Package...を選択します。 1. Brawseをクリックし、DebugTraceで検索して表示されたリストからDebugTraceを選択してインストールします。

対象のメソッドとテストメソッドにDebugTrace-netのメソッドを呼び出すコードを挿入します。

using System.Text;
using static DebugTrace.CSharp; // TODO: Delete after debugging

namespace DebugTraceTutorial {
    public class Tutorial1 {
        public static int MaxLogByteArrayLength = 1024;

        /// <summary>
        /// バイト配列の文字列表現をStringBuilderに追加する。
        /// </summary>
        /// <param name="builder">StringBuilder</param>
        /// <param name="bytes">バイト配列</param>
        /// <returns>引数のbuilder</returns>
        public static StringBuilder AppendBytes(StringBuilder builder, byte[] bytes) {
            Trace.Enter(); // TODO: Delete after debugging
            Trace.Print("bytes", bytes); // TODO: Delete after debugging
            builder.Append('[');
            var delimiter = "";
            for (var index = 0; index < bytes.Length; ++index) {
                Trace.Print("index", index); // TODO: Delete after debugging
                builder.Append(delimiter);
                if (index >= MaxLogByteArrayLength) {
                    builder.Append("...");
                    break;
                }
                var value = bytes[index];
                Trace.Print("value", value); // TODO: Delete after debugging
                var ch = (char)(value / 16 + '0');
                Trace.Print("1-1 ch", ch); // TODO: Delete after debugging
                if (ch >= '9') ch += (char)('A' - '9' - 1);
                Trace.Print("1-2 ch", ch); // TODO: Delete after debugging
                builder.Append(ch);
                ch = (char)(value % 16 + '0');
                Trace.Print("2-1 ch", ch); // TODO: Delete after debugging
                if (ch >= '9') ch += (char)('A' - '9' - 1);
                Trace.Print("2-2 ch", ch); // TODO: Delete after debugging
                builder.Append(ch);
                delimiter = ", ";
            }
            builder.Append(']');
            Trace.Leave(); // TODO: Delete after debugging
            return builder;
        }
    }
}
using DebugTraceTutorial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text;
using static DebugTrace.CSharp; // TODO: Delete after debugging

namespace DebugtraceTutorial {
    [TestClass]
    public class Tutorial1Test {
        /**
         * appendBytesのテスト。
         * @param bytes バイト配列
         * @param expected StringBuilderに追加されると期待する文字列
         */
        [DataTestMethod]
        [DataRow(new byte[] {}, "[]")]
        [DataRow(new byte[] {1}, "[01]")]
        [DataRow(
            new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
            "[00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F]"
        )]
        [DataRow(
            new byte[] {0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF},
            "[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, FA, FB, FC, FD, FE, FF]"
        )]
        public void TestAppendBytes(byte[] bytes, string expected) {
            Trace.Enter(); // TODO: Delete after debugging
            Trace.Print("bytes", bytes); // TODO: Delete after debugging
            Trace.Print("expected", expected); // TODO: Delete after debugging
            // when
            var builder = Tutorial1.AppendBytes(new StringBuilder(), bytes);

            // then
            Assert.AreEqual(expected, builder.ToString());
            Trace.Leave(); // TODO: Delete after debugging
        }
    }
}

もう一度テストを実行してみます。以下は上記を実行したログの一部です。ログはデフォルトで標準エラー(stderr)に出力されます。
Text ExplorerTest Detail SummaryからOpen additional output for this resultをクリッすると出力内容を確認できます。

2020-11-22 12:03:32.798 [04] Enter DebugtraceTutorial.Tutorial1Test.TestAppendBytes(Byte[] bytes, String expected) (Tutorial1Test.cs:28)
2020-11-22 12:03:32.799 [04] | 
2020-11-22 12:03:32.799 [04] | bytes =
2020-11-22 12:03:32.799 [04] | byte[16] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} (Tutorial1Test.cs:29)
2020-11-22 12:03:32.799 [04] | 
2020-11-22 12:03:32.799 [04] | expected =
2020-11-22 12:03:32.799 [04] | (Length:64)"[00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0
2020-11-22 12:03:32.799 [04] | E, 0F]" (Tutorial1Test.cs:30)
2020-11-22 12:03:32.800 [04] | Enter DebugTraceTutorial.Tutorial1.AppendBytes(StringBuilder builder, Byte[] bytes) (Tutorial1.cs:17)
2020-11-22 12:03:32.800 [04] | | 
2020-11-22 12:03:32.800 [04] | | bytes =
2020-11-22 12:03:32.800 [04] | | byte[16] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} (Tutorial1.cs:18)
2020-11-22 12:03:32.800 [04] | | 
2020-11-22 12:03:32.800 [04] | | index = 0 (Tutorial1.cs:22)
2020-11-22 12:03:32.800 [04] | | value = byte 0 (Tutorial1.cs:29)
2020-11-22 12:03:32.801 [04] | | 1-1 ch = '0' (Tutorial1.cs:31)
2020-11-22 12:03:32.801 [04] | | 1-2 ch = '0' (Tutorial1.cs:33)
2020-11-22 12:03:32.801 [04] | | 2-1 ch = '0' (Tutorial1.cs:36)
2020-11-22 12:03:32.802 [04] | | 2-2 ch = '0' (Tutorial1.cs:38)
    ...
2020-11-22 12:03:32.822 [04] | | index = 9 (Tutorial1.cs:22)
2020-11-22 12:03:32.822 [04] | | value = byte 9 (Tutorial1.cs:29)
2020-11-22 12:03:32.822 [04] | | 1-1 ch = '0' (Tutorial1.cs:31)
2020-11-22 12:03:32.824 [04] | | 1-2 ch = '0' (Tutorial1.cs:33)
2020-11-22 12:03:32.825 [04] | | 2-1 ch = '9' (Tutorial1.cs:36)
2020-11-22 12:03:32.826 [04] | | 2-2 ch = '@' (Tutorial1.cs:38)
    ...

バイト配列の9の2桁目が'9'であるはずが'@'に間違って変換されています。 これはif (ch >= '9')の判定が間違っているのでif (ch > '9')に修正します。

修正後もう一度テストを実行すると成功します。ログの一部は以下になります。

2020-11-22 12:04:41.466 [05] | | index = 9 (Tutorial1.cs:22)
2020-11-22 12:04:41.466 [05] | | value = byte 9 (Tutorial1.cs:29)
2020-11-22 12:04:41.466 [05] | | 1-1 ch = '0' (Tutorial1.cs:31)
2020-11-22 12:04:41.468 [05] | | 1-2 ch = '0' (Tutorial1.cs:33)
2020-11-22 12:04:41.468 [05] | | 2-1 ch = '9' (Tutorial1.cs:36)
2020-11-22 12:04:41.468 [05] | | 2-2 ch = '9' (Tutorial1.cs:38)

デバッグの終了後にデバッグ用コードを削除するには、正規表現で検索して空文字列に置換します。改行コードも削除しているのでデバッグ用コードを挿入する前のソースに戻ります。

正規表現検索文字列: ^.+(Debug)?Trace\..*\r?\n

チュートリアル2

次のチュートリアルのソースとテストソースは以下です。
パス: DebugTraceNetTutorial\Tutorial\src\Tutorial2.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace DebugTraceTutorial {
    public class Tutorial2 {
        private static Dictionary<Type, string> shortNames = new Dictionary<Type, string>() {
            {typeof(void)   , "void"   }, {typeof(bool)  , "bool"  },
            {typeof(sbyte)  , "sbyte"  }, {typeof(byte)  , "byte"  },
            {typeof(short)  , "short"  }, {typeof(ushort), "ushort"},
            {typeof(int)    , "int"    }, {typeof(uint)  , "uint"  },
            {typeof(long)   , "long"   }, {typeof(ulong) , "ulong" },
            {typeof(float)  , "float"  }, {typeof(double), "double"},
            {typeof(decimal), "decimal"},
            {typeof(char)   , "char"   }, {typeof(string), "string"},
        };

        /// <summary>
        /// 型名を返します。ただしSystem名前空間の場合は名前空間を取り除いて返します。
        /// </summary>
        /// <param name="type"></param>
        /// <returns>型名</returns>
        public static string GetName(Type type) {
            if (shortNames.ContainsKey(type)) return shortNames[type];
            if (type.IsArray) return GetName(type.GetElementType()) + "[]";
            var typeArguments = type.GenericTypeArguments;
            var backets = ("", "");
            var isValueTuple = type == typeof(ValueTuple);
            if (typeArguments.Length > 0)
                backets = isValueTuple ? ("(", ")") : ("<", ">");
            var builder = new StringBuilder();
            if (!isValueTuple) {
                var typeName = type.Namespace == "System" ? type.Name : type.FullName;
                var backquoteIndex = typeName.IndexOf('`');
                if (backquoteIndex >= 0)
                    typeName = typeName.Substring(0, backquoteIndex);
                builder.Append(typeName);
            }
            builder.Append(backets.Item1);
            var delimiter = "";
            foreach (var typeArgument in typeArguments) {
                builder.Append(delimiter).Append(GetName(typeArgument));
                delimiter = ", ";
            }
            builder.Append(backets.Item2);
            return builder.ToString();
        }
    }
}

パス: DebugTraceNetTutorial\TutorialTest\src\Tutorial2Test.cs

using DebugTraceTutorial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Data;

namespace DebugtraceTutorial {
    [TestClass]
    public class Tutorial2Test {
        /**
         * GetNameのテスト。
         * @param type 対象の型
         * @param expected 予期する型名
         */
        [DataTestMethod]
        /* 1 */ [DataRow(typeof(string), "string")]
        /* 2 */ [DataRow(typeof(string[]), "string[]")]
        /* 3 */ [DataRow(typeof(string[][]), "string[][]")]
        /* 4 */ [DataRow(typeof(List<string>), "System.Collections.Generic.List<string>")]
        /* 5 */ [DataRow(typeof(List<string>[]), "System.Collections.Generic.List<string>[]")]
        /* 6 */ [DataRow(typeof((int, long)), "(int, long)")]
        /* 7 */ [DataRow(typeof(((byte, short), (int, long))), "((byte, short), (int, long))")]
        public void TestGetName(Type type, string expected) {
            // when
            var typeName = Tutorial2.GetName(type);

            // then
            Assert.AreEqual(expected, typeName);
        }
    }
}

実行すると最初の5つで成功しますが、後の2つ(ValueTuple)では失敗します。

テスト結果(最初の失敗):

Assert.AreEqual failed. Expected:<(int, long)>. Actual:<ValueTuple<int, long>>.

デバッグコードを挿入しますが、メソッドが終了する箇所が3箇所あるため、Trace.Leaveメソッドの呼び出しをGetNameメソッドの最後に挿入だけでは不十分です。 この場合は、以下のようにします。

using System;
using System.Collections.Generic;
using System.Text;
using static DebugTrace.CSharp; // TODO: Delete after debugging

namespace DebugTraceTutorial {
    public class Tutorial2 {
        private static Dictionary<Type, string> shortNames = new Dictionary<Type, string>() {
            {typeof(void)   , "void"   }, {typeof(bool)  , "bool"  },
            {typeof(sbyte)  , "sbyte"  }, {typeof(byte)  , "byte"  },
            {typeof(short)  , "short"  }, {typeof(ushort), "ushort"},
            {typeof(int)    , "int"    }, {typeof(uint)  , "uint"  },
            {typeof(long)   , "long"   }, {typeof(ulong) , "ulong" },
            {typeof(float)  , "float"  }, {typeof(double), "double"},
            {typeof(decimal), "decimal"},
            {typeof(char)   , "char"   }, {typeof(string), "string"},
        };

        /// <summary>
        /// 型名を返します。ただしSystem名前空間の場合は名前空間を取り除いて返します。
        /// </summary>
        /// <param name="type"></param>
        /// <returns>型名</returns>
        public static string GetName(Type type) {
            try {Trace.Enter(); // TODO: Delete after debugging
            Trace.Print("type", type); // TODO: Delete after debugging
            if (shortNames.ContainsKey(type)) return shortNames[type];
            if (type.IsArray) return GetName(type.GetElementType()) + "[]";
            var typeArguments = type.GenericTypeArguments;
            Trace.Print("typeArguments", typeArguments); // TODO: Delete after debugging
            var backets = ("", "");
            var isValueTuple = type == typeof(ValueTuple);
            Trace.Print("typeof(ValueTuple)", typeof(ValueTuple)); // TODO: Delete after debugging
            Trace.Print("isValueTuple", isValueTuple); // TODO: Delete after debugging
            if (typeArguments.Length > 0)
                backets = isValueTuple ? ("(", ")") : ("<", ">");
            Trace.Print("backets", backets); // TODO: Delete after debugging
            var builder = new StringBuilder();
            if (!isValueTuple) {
                var typeName = type.Namespace == "System" ? type.Name : type.FullName;
                var backquoteIndex = typeName.IndexOf('`');
                if (backquoteIndex >= 0)
                    typeName = typeName.Substring(0, backquoteIndex);
                builder.Append(typeName);
            }
            builder.Append(backets.Item1);
            var delimiter = "";
            foreach (var typeArgument in typeArguments) {
                builder.Append(delimiter).Append(GetName(typeArgument));
                delimiter = ", ";
            }
            builder.Append(backets.Item2);
            return builder.ToString();
            } finally {Trace.Leave();} // TODO: Delete after debugging
        }
    }
}

テスト対象のメソッド全体をtry {Trace.Enter();} finally {Trace.Leave();}で囲います。 テストメソッドの方はチュートリアル1と同様にします。
テストを実行すると以下のログ(失敗している部分)が出力されます。

2020-11-22 19:05:52.115 [04] Enter DebugtraceTutorial.Tutorial2Test.TestGetName(Type type, String expected) (Tutorial2Test.cs:27)
2020-11-22 19:05:52.115 [04] | 
2020-11-22 19:05:52.115 [04] | type =
2020-11-22 19:05:52.115 [04] | System.RuntimeType System.ValueTuple`2[System.Int32,System.Int64] (Tutorial2Test.cs:28)
2020-11-22 19:05:52.115 [04] | 
2020-11-22 19:05:52.115 [04] | expected = (Length:11)"(int, long)" (Tutorial2Test.cs:29)
2020-11-22 19:05:52.116 [04] | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:05:52.116 [04] | | 
2020-11-22 19:05:52.116 [04] | | type =
2020-11-22 19:05:52.116 [04] | | System.RuntimeType System.ValueTuple`2[System.Int32,System.Int64] (Tutorial2.cs:28)
2020-11-22 19:05:52.118 [04] | | 
2020-11-22 19:05:52.118 [04] | | typeArguments = System.Type[2] {
2020-11-22 19:05:52.118 [04] | |   System.RuntimeType System.Int32, System.RuntimeType System.Int64
2020-11-22 19:05:52.118 [04] | | } (Tutorial2.cs:32)
2020-11-22 19:05:52.119 [04] | | 
2020-11-22 19:05:52.119 [04] | | typeof(ValueTuple) = System.RuntimeType System.ValueTuple (Tutorial2.cs:35)
2020-11-22 19:05:52.119 [04] | | isValueTuple = false (Tutorial2.cs:36)
2020-11-22 19:05:52.120 [04] | | backets = ("<", ">") (Tutorial2.cs:40)
2020-11-22 19:05:52.120 [04] | | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:05:52.120 [04] | | | type = System.RuntimeType System.Int32 (Tutorial2.cs:28)
2020-11-22 19:05:52.121 [04] | | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0003259
2020-11-22 19:05:52.121 [04] | | 
2020-11-22 19:05:52.121 [04] | | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:05:52.124 [04] | | | type = System.RuntimeType System.Int64 (Tutorial2.cs:28)
2020-11-22 19:05:52.124 [04] | | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0028577
2020-11-22 19:05:52.124 [04] | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0085159

テストの最後のLeaveの出力がないのは、テストが失敗した場合は、途中で例外がスローされてテストメソッドのTrace.Leave()が呼ばれないためです。そこでテストメソッドもtry {}finally{}を使用します。

using DebugTraceTutorial;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Data;
using static DebugTrace.CSharp; // TODO: Delete after debugging

namespace DebugtraceTutorial {
    [TestClass]
    public class Tutorial2Test {
        /**
         * GetNameのテスト。
         * @param type 対象の型
         * @param expected 予期する型名
         */
        [DataTestMethod]
        /* 1 */ [DataRow(typeof(string), "string")]
        /* 2 */ [DataRow(typeof(string[]), "string[]")]
        /* 3 */ [DataRow(typeof(string[][]), "string[][]")]
        /* 4 */ [DataRow(typeof(List<string>), "System.Collections.Generic.List<string>")]
        /* 5 */ [DataRow(typeof(List<string>[]), "System.Collections.Generic.List<string>[]")]
        /* 6 */ [DataRow(typeof((int, long)), "(int, long)")]
        /* 7 */ [DataRow(typeof(((byte, short), (int, long))), "((byte, short), (int, long))")]
        public void TestGetName(Type type, string expected) {
            try {Trace.Enter(); // TODO: Delete after debugging
            Trace.Print("type", type); // TODO: Delete after debugging
            Trace.Print("expected", expected); // TODO: Delete after debugging
            // when
            var typeName = Tutorial2.GetName(type);

            // then
            Assert.AreEqual(expected, typeName);
            } finally {Trace.Leave();} // TODO: Delete after debugging
        }
    }
}

実行してみます。

2020-11-22 19:14:25.609 [04] Enter DebugtraceTutorial.Tutorial2Test.TestGetName(Type type, String expected) (Tutorial2Test.cs:27)
2020-11-22 19:14:25.609 [04] | 
2020-11-22 19:14:25.609 [04] | type =
2020-11-22 19:14:25.609 [04] | System.RuntimeType System.ValueTuple`2[System.Int32,System.Int64] (Tutorial2Test.cs:28)
2020-11-22 19:14:25.609 [04] | 
2020-11-22 19:14:25.609 [04] | expected = (Length:11)"(int, long)" (Tutorial2Test.cs:29)
2020-11-22 19:14:25.610 [04] | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:14:25.610 [04] | | 
2020-11-22 19:14:25.610 [04] | | type =
2020-11-22 19:14:25.610 [04] | | System.RuntimeType System.ValueTuple`2[System.Int32,System.Int64] (Tutorial2.cs:28)
2020-11-22 19:14:25.612 [04] | | 
2020-11-22 19:14:25.612 [04] | | typeArguments = System.Type[2] {
2020-11-22 19:14:25.612 [04] | |   System.RuntimeType System.Int32, System.RuntimeType System.Int64
2020-11-22 19:14:25.612 [04] | | } (Tutorial2.cs:32)
2020-11-22 19:14:25.613 [04] | | 
2020-11-22 19:14:25.613 [04] | | typeof(ValueTuple) = System.RuntimeType System.ValueTuple (Tutorial2.cs:35)
2020-11-22 19:14:25.614 [04] | | isValueTuple = false (Tutorial2.cs:36)
2020-11-22 19:14:25.614 [04] | | backets = ("<", ">") (Tutorial2.cs:40)
2020-11-22 19:14:25.614 [04] | | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:14:25.615 [04] | | | type = System.RuntimeType System.Int32 (Tutorial2.cs:28)
2020-11-22 19:14:25.615 [04] | | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0003853
2020-11-22 19:14:25.615 [04] | | 
2020-11-22 19:14:25.615 [04] | | Enter DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:27)
2020-11-22 19:14:25.619 [04] | | | type = System.RuntimeType System.Int64 (Tutorial2.cs:28)
2020-11-22 19:14:25.619 [04] | | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0031286
2020-11-22 19:14:25.619 [04] | Leave DebugTraceTutorial.Tutorial2.GetName(Type type) (Tutorial2.cs:26) duration: 00:00:00.0090726
2020-11-22 19:14:25.622 [04] Leave DebugtraceTutorial.Tutorial2Test.TestGetName(Type type, String expected) (Tutorial2Test.cs:34) duration: 00:00:00.0128997

テストが失敗する原因は、typeValueTupleの場合は、trueになって欲しいvar isValueTuple = type == typeof(ValueTuple);が原因なので、var isValueTuple = type.FullName.StartsWith("System.ValueTuple");に修正します。

デバッグ終了後は、チュートリアル1と同様にデバッグ用コードを削除します。

まとめ

  • チュートリアル1: デバッグコードを挿入する対象のメソッドの終了箇所が1箇所でかつ例外をスローしない場合
    (または例外がスローされた場合にインデントが正しくなくても良い場合)
  • チュートリアル2: デバッグコードを挿入する対象のメソッドの終了箇所が複数か途中で例外をスローする可能性がある場合

以上でチュートリアルは終了です。