次の方法で共有


初心者向けのデバッグ

ソフトウェア開発者として記述するコードは、必ずしも期待どおりに動作するとは限りません。 時には、それは全く異なる何かを行います! 予期しない状況が発生した場合、次のタスクは理由を見つけ出す作業です。また、コードを何時間も見つめ続けたくなるかもしれませんが、デバッグ ツールまたはデバッガーを使用する方が簡単で効率的です。

残念ながら、デバッガーは、コード内のすべての問題や "バグ" を魔法のように明らかにできるものではありません。 デバッグ とは、Visual Studio などのデバッグ ツールでコードを段階的に実行し、プログラミングミスを犯した正確なポイントを見つけることを意味します。 その後、コードおよびデバッグ ツールで行う必要がある修正内容を理解すると、多くの場合、プログラムの実行を続行できるように一時的な変更を行うことができます。

デバッガーを効果的に使用することは、学習に時間と練習を要するスキルでもありますが、最終的にはすべてのソフトウェア開発者にとって基本的なタスクです。 この記事では、デバッグの基本原則を紹介し、開始するためのヒントを提供します。

自分に正しい質問をして問題を明確にする

修正を試みる前に発生した問題を明確にするのに役立ちます。 コードで既に問題が発生していることを想定しています。そうしないと、デバッグ方法を理解しようとはならないでしょう。 そのため、デバッグを開始する前に、解決しようとしている問題が特定されていることを確認してください。

  • コードで何を行うと予想されましたか?

  • 代わりに何が起こりましたか?

    アプリの実行中にエラー(例外)が発生した場合、それは良いことかもしれません! 例外は、コードの実行時に予期しないイベントが発生し、通常は何らかのエラーが発生します。 デバッグ ツールを使用すると、例外が発生したコード内の正確な場所に行き、考えられる修正プログラムを調査するのに役立ちます。

    何か他の問題が発生した場合、問題の症状は何ですか? コードでこの問題が発生した場所を既に疑っていますか? たとえば、コードにテキストが表示されていても、テキストが正しくない場合は、データが正しくないか、表示テキストを設定するコードに何らかのバグがあることがわかります。 デバッガーでコードをステップ実行することで、変数に対する各変更を調べて、正しくない値が割り当てられているタイミングと方法を正確に検出できます。

前提条件を調べる

バグやエラーを調査する前に、特定の結果が予想される前提条件を考えてください。 デバッガーで問題の原因を調べているときでも、非表示または不明な仮定が問題の特定を妨げることがあります。 考えられる前提条件の長いリストがあるかもしれません。 前提条件に挑戦するために自分自身に質問する必要がある質問をいくつか次に示します。

  • 適切な API (つまり、適切なオブジェクト、関数、メソッド、またはプロパティ) を使用していますか? 使用している API は、思った動作を行わない可能性があります。 (デバッガーで API 呼び出しを調べた後、修正するには、正しい API を識別するためにドキュメントへの旅行が必要な場合があります)。

  • API を正しく使用していますか? おそらく、適切な API を使用しましたが、正しい方法で使用しませんでした。

  • コードに入力ミスが含まれていますか? 変数名の単純なスペルミスなど、一部の入力ミスは、特に変数を使用する前に宣言する必要のない言語を使用する場合に、見にくい場合があります。

  • コードに変更を加え、それが表示されている問題とは無関係であると想定しましたか?

  • 実際に発生した内容とは異なる特定の値 (または特定の型の値) がオブジェクトまたは変数に含まれていることが予想されましたか?

  • コードの意図を知っていますか? 多くの場合、他のユーザーのコードをデバッグすることはより困難です。 コードでない場合は、コードを効果的にデバッグする前に、コードの動作を正確に学習するために時間を費やす必要がある可能性があります。

    ヒント

    コードを記述するときは、小さく始めて、動作するコードから始めてください。 (ここでは、適切なサンプル コードが役立ちます)。場合によっては、達成しようとしているコア タスクを示す小さなコードから始めることで、大規模または複雑なコード セットを修正する方が簡単な場合があります。 その後、コードを段階的に変更または追加し、各時点でエラーをテストできます。

想定に疑問を投げかけることで、コードで問題を見つけるのにかかる時間を短縮できます。 また、問題の解決にかかる時間を短縮することもできます。

デバッグ モードでコードをステップ実行して、問題が発生した場所を見つけます

通常、アプリを実行すると、コードの実行後にのみエラーと正しくない結果が表示されます。 また、理由を伝えずに、プログラムが予期せず終了する場合もあります。

デバッグ モードとも呼ばれるデバッガー内でアプリ 実行すると、デバッガーはプログラムの実行時に発生するすべてのことをアクティブに監視します。 また、アプリを任意の時点で一時停止して状態を確認し、コードを 1 行ずつステップ実行して、すべての詳細を確認することもできます。

Visual Studio では、 F5 キーを押してデバッグ モードに切り替えます (または[ デバッグ>デバッグの開始 ] メニュー コマンドを使用するか、[デバッグの 開始 ] ボタンを 示す [デバッグの開始] ボタンアイコン を使用します。デバッグ ツール バー)。 例外が発生した場合、Visual Studio の例外ヘルパーは、例外が発生した正確なポイントに移動し、他の役に立つ情報を提供します。 コード内の例外を処理する方法の詳細については、「デバッグ手法とツールの」を参照してください。

例外が発生しなかった場合は、コード内の問題を探す場所を適切に把握している可能性があります。 この手順では、デバッガーで ブレークポイント を使用して、コードをより慎重に調べることができます。 ブレークポイントは、信頼性の高いデバッグの最も基本的で不可欠な機能です。 ブレークポイントは、Visual Studio で実行中のコードを一時停止する場所を示します。そのため、コードが実行されるシーケンスの変数の値またはメモリの動作を確認できます。

Visual Studio では、コード行の横にある左余白をクリックすると、ブレークポイントをすばやく設定できます。 または、行にカーソルを置き、 F9 キーを押します。

これらの概念を説明するために、既にいくつかのバグがあるコード例を説明します。 C# を使用していますが、デバッグ機能は Visual Basic、C++、JavaScript、Python、およびその他のサポートされている言語に適用されます。 Visual Basic のサンプル コードも提供されていますが、スクリーンショットは C# にあります。

サンプル アプリを作成する (いくつかのバグあり)

次に、いくつかのバグがあるアプリケーションを作成します。

  1. Visual Studio がインストールされ、 .NET デスクトップ開発 ワークロードがインストールされている必要があります。

    Visual Studio をまだインストールしていない場合は、Visual Studio のダウンロード ページに移動して無料でインストールします。

    ワークロードをインストールする必要があるが、Visual Studio が既にある場合は、[ ツール]>[ツールと機能の取得] を選択します。 Visual Studio インストーラーが起動します。 .NET デスクトップ開発ワークロードを選択し、[変更] を選択します。

  2. Visual Studio を開きます。

    スタート ウィンドウで、[新しいプロジェクト作成] を選択します。 検索ボックスに コンソール を入力し、言語として C# または Visual Basic を選択し、[.NET 用 コンソール アプリ ] を選択します。 [次へ] を選択します。 プロジェクト名として ConsoleApp_FirstApp 入力し、[ 次へ] を選択します。

    別のプロジェクト名を使用する場合は、サンプル コードをコピーするときに、プロジェクト名と一致するように名前空間の値を変更する必要があります。

    推奨されるターゲット フレームワークまたは .NET 8 を選択し、次に 作成を選択します。

    .NET 用の コンソール アプリ プロジェクト テンプレートが表示されない場合は、[ツール]>[ツールと機能の取得]に移動すると、Visual Studio インストーラーが開きます。 .NET デスクトップ開発ワークロードを選択し、[変更] を選択します。

    Visual Studio によってコンソール プロジェクトが作成され、右側のウィンドウ ソリューション エクスプローラー に表示されます。

  3. Program.cs (またはProgram.vb) で、すべての既定のコードを次のコードに置き換えます。 (最初に、適切な言語タブ (C# または Visual Basic) を選択します)。

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    このコードの目的は、銀河名、銀河までの距離、および銀河の種類をすべて一覧に表示することです。 デバッグするには、コードの意図を理解することが重要です。 出力に表示するリストの 1 行の形式を次に示します。

    銀河名距離銀河の種類

アプリを実行する

F5 キーを押すか、コード エディターの上にあるデバッグ ツール バーの [デバッグの開始] ボタンを示す [デバッグの開始] ボタン アイコンを押します。

アプリが起動し、デバッガーには例外が表示されません。 ただし、コンソール ウィンドウに表示される出力は期待した内容ではありません。 予想される出力を次に示します。

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

ただし、代わりに次の出力が表示されます。

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

出力とコードを見ると、 GType は銀河型を格納するクラスの名前であることがわかります。 クラス名ではなく、実際の銀河の種類 ("スパイラル" など) を表示しようとしています。

アプリをデバッグする

  1. アプリがまだ実行されている状態で、ブレークポイントを挿入します。

    foreach ループで、Console.WriteLine メソッドの横を右クリックしてコンテキスト メニューを取得し、ポップアップ メニューから [>ブレークポイントの挿入] を選択します。

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    ブレークポイントを設定すると、左側の余白に赤い点が表示されます。

    出力に問題がある場合は、デバッガーで出力を設定する上記のコードを参照してデバッグを開始します。

  2. [Icon showing RestartApp button in Debug toolbar.を選択します。デバッグ ツール バーのボタン (Ctrl + + )。

    設定したブレークポイントでアプリが一時停止します。 黄色の強調表示は、デバッガーが一時停止されている場所を示します (黄色のコード行はまだ実行されていません)。

  3. 右側の GalaxyType 変数にカーソルを合わせた後、レンチアイコンの左側にある theGalaxy.GalaxyType を展開します。 GalaxyTypeにプロパティ MyGTypeが含まれており、プロパティ値が Spiral に設定されていることがわかります。

    Visual Studio デバッガーのスクリーンショット。コード行が黄色で、Galaxy GalaxyType プロパティの下にメニューが開いています。

    "スパイラル" は、実際にはコンソールに印刷する予定だった正しい値です。 そのため、アプリの実行中にこのコードの値にアクセスできることは良いスタートです。 このシナリオでは、正しくない API を使用しています。 デバッガーでコードを実行しているときにこれを修正できるかどうかを見てみましょう。

  4. 同じコードで、デバッグ中にカーソルを theGalaxy.GalaxyType の最後に置き、 theGalaxy.GalaxyType.MyGTypeに変更します。 編集はできますが、コード エディターにエラー (赤い波線) が表示されます。 (Visual Basic では、エラーは表示されず、コードのこのセクションは機能します)。

  5. F11 (デバッグ>ステップ インまたはデバッグ ツール バーのステップ イン ボタン) を押して、現在のコード行を実行します。

    F11 は、デバッガーを一度に 1 つのステートメントに進めます (コードを実行します)。 F10 (ステップ オーバー) も同様のコマンドであり、どちらもデバッガーの使用方法を学習するときに役立ちます。

    デバッガーを進めようとすると、[ホット リロード] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。

    Visual Studio デバッガーのスクリーンショット。コード行が赤で強調表示され、[編集] オプションが選択されたメッセージ ボックスが表示されています。

    [エディット コンティニュ] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。

    Visual Studio デバッガーのスクリーンショット。コード行が赤で強調表示され、[編集] オプションが選択されたメッセージ ボックスが表示されています。

    Visual Basic サンプル コードをデバッグする場合は、Icon showing Restart app button in Debug toolbar.[再起動] アイコンをクリックするように指示されるまで、次のいくつかの手順をスキップします。

  6. ホット リロード または 編集して続行 メッセージ ボックスで [編集] を選択します。 [エラー 一覧 ] ウィンドウにエラー メッセージが表示されます。 このエラーは、 'object'MyGTypeの定義が含まれていないことを示します。

    Visual Studio デバッガーのスクリーンショット。コード行が赤で強調表示され、エラー一覧ウィンドウに 2 つのエラーが表示されています。

    各銀河に GType 型のオブジェクト ( MyGType プロパティを持つ) を設定しても、デバッガーは theGalaxy オブジェクトを GType型のオブジェクトとして認識しません。 何が起こっているのでしょうか? 銀河の種類を設定するコードを確認したい。 これを行うと、 GType クラスに MyGTypeのプロパティが確実に含まれているのに、何かが正しくないことがわかります。 objectに関するエラー メッセージが手掛かりであることが判明しました。言語インタープリターの場合、型はobject型のオブジェクトではなく、GType型のオブジェクトのように見えます。

  7. 銀河の種類の設定に関連するコードを調べると、GalaxyType クラスのGalaxyプロパティがobjectではなくGTypeとして指定されていることがわかります。

    public object GalaxyType { get; set; }
    
  8. 上記のコードを次のように変更します。

    public GType GalaxyType { get; set; }
    
  9. [Icon showing Restart app button in Debug toolbar.再起動アイコンを選択します。コードを再コンパイルして再起動するには、デバッグ ツール バー (Ctrl + Shift + F5) のボタンをクリックします。

    これで、デバッガーが Console.WriteLineで一時停止したときに、 theGalaxy.GalaxyType.MyGType上にマウス ポインターを合わせ、値が正しく設定されていることを確認できます。

  10. ブレークポイントを削除するには、左余白にあるブレークポイントの円をクリックして (または右クリックして [ ブレークポイント>ブレークポイントの削除])、 F5 キーを押して続行します。

    アプリが実行され、出力が表示されます。 見栄えは良いですが、1 つのことに気付きます。 あなたは、小さなマゼラン雲の銀河がコンソール出力に不規則な銀河として現れるのを期待しましたが、それは全く銀河の種類を示していません。

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. switch ステートメントの前 (Visual Basic の Select ステートメントの前) に、このコード行にブレークポイントを設定します。

    public GType(char type)
    

    このコードは銀河の種類が設定されている場所であるため、詳しく見てみたいと思います。

  12. [Icon showing Restart app button in Debug toolbar.[再起動] アイコンを選択します。再起動するには、デバッグ ツール バー (Ctrl + Shift + F5) のボタンをクリックします。

    デバッガーは、ブレークポイントを設定したコード行で一時停止します。

  13. type変数にカーソルを合わせます。 Sの値が表示されます (文字コードの後)。 不規則な銀河型であることがわかっているので、 Iの値に興味があります。

  14. F5 キーを押し、もう一度type変数の上にカーソルを合わせます。 I変数に type の値が表示されるまで、この手順を繰り返します。

    Visual Studio デバッガーのスクリーンショット。コード行が黄色で、ウィンドウの型変数値が 73 I です。

  15. 次に、 F11 キーを押します (Debug>Step Into)。

  16. 値 'I' の ステートメントのコード行で停止するまで F11 キーを押し続けます (Visual Basic の場合は ステートメント). ここでは、入力ミスの結果として生じる明確な問題が表示されます。 コードはMyGTypeを不規則な銀河型として設定する場所に進む必要がありますが、代わりにデバッガーはこのコードを完全にスキップし、default ステートメントのswitchセクション (Visual Basic のElseステートメント) で一時停止します。

    入力ミス エラーを示すスクリーンショット。

    コードを見ると、 case 'l' ステートメントに入力ミスが表示されます。 case 'I'する必要があります。

  17. case 'l'のコードを選択し、case 'I'に置き換えます。

  18. ブレークポイントを削除し、[ 再起動 ] ボタンを選択してアプリを再起動します。

    バグが修正され、期待される出力が表示されます。

    任意のキーを押してアプリを終了します。

概要

問題が発生した場合は、デバッガーと F10F11 などのステップ コマンドを使用して、問題のあるコードの領域を見つけます。

問題が発生したコードの領域を特定することが困難な場合は、問題が発生する前に実行されるコードにブレークポイントを設定し、問題のマニフェストが表示されるまでステップ コマンドを使用します。 トレースポイントを使用して、メッセージを出力ウィンドウに記録することもできます。 ログに記録されたメッセージを調べて (まだログに記録されていないメッセージを確認します)、多くの場合、問題のあるコードの領域を特定できます。 このプロセスを何度か繰り返して絞り込む必要がある場合があります。

問題のあるコードの領域が見つかると、デバッガーを使用して調査します。 問題の原因を見つけるには、デバッガーでアプリを実行しているときに問題のコードを調べます。

  • 変数を検査 し、変数に含める必要がある値の型が含まれているかどうかを確認します。 正しくない値が見つかると、正しくない値が設定された場所を確認します (値が設定された場所を見つけるには、デバッガーを再起動するか、 呼び出し履歴を確認するか、またはその両方が必要になる場合があります)。

  • アプリケーションが想定したコードを実行しているかどうかを確認します。 (たとえば、サンプル アプリケーションでは、 switch ステートメントのコードで銀河の種類を [不規則] に設定することが想定されていましたが、入力ミスが原因でアプリによってコードがスキップされました)。

ヒント

バグを見つけるのに役立つデバッガーを使用します。 デバッグ ツールは、コード 意図を認識している場合にのみ、バグを見つけることができます。 ツールは、開発者がその意図を表現している場合にのみ、コードの意図を知ることができます。 単体テストの作成は、その方法です。

次のステップ

この記事では、いくつかの一般的なデバッグの概念について学習しました。 次に、デバッガーの詳細について学習を開始できます。