ソフトウェア開発者として記述するコードは、必ずしも期待どおりに動作するとは限りません。 時には、それは全く異なる何かを行います! 予期しない状況が発生した場合、次のタスクは理由を見つけ出す作業です。また、コードを何時間も見つめ続けたくなるかもしれませんが、デバッグ ツールまたはデバッガーを使用する方が簡単で効率的です。
残念ながら、デバッガーは、コード内のすべての問題や "バグ" を魔法のように明らかにできるものではありません。 デバッグ は、Visual Studio などのデバッグ ツールでコードを段階的に実行し、プログラミングミスを犯した正確なポイントを見つけることを意味します。 その後、コードおよびデバッグ ツールで行う必要がある修正内容を理解すると、多くの場合、プログラムの実行を続行できるように一時的な変更を行うことができます。
デバッガーを効果的に使用することは、学習に時間と練習を要するスキルでもありますが、最終的にはすべてのソフトウェア開発者にとって基本的なタスクです。 この記事では、デバッグの基本原則を紹介し、開始するためのヒントを提供します。
自分に正しい質問をして問題を明確にする
修正を試みる前に発生した問題を明確にするのに役立ちます。 コードで既に問題が発生していることを想定しています。そうしないと、デバッグ方法を理解しようとはならないでしょう。 そのため、デバッグを開始する前に、解決しようとしている問題が特定されていることを確認してください。
コードで何を行うと予想されましたか?
代わりに何が起こりましたか?
アプリの実行中にエラー(例外)が発生した場合、それは良いことかもしれません! 例外は、コードの実行時に予期しないイベントが発生し、通常は何らかのエラーが発生します。 デバッグ ツールを使用すると、例外が発生したコード内の正確な場所に行き、考えられる修正プログラムを調査するのに役立ちます。
何か他の問題が発生した場合、問題の症状は何ですか? コードでこの問題が発生した場所を既に疑っていますか? たとえば、コードにテキストが表示されていても、テキストが正しくない場合は、データが正しくないか、表示テキストを設定するコードに何らかのバグがあることがわかります。 デバッガーでコードをステップ実行することで、変数に対する各変更を調べて、正しくない値が割り当てられているタイミングと方法を正確に検出できます。
前提条件を調べる
バグやエラーを調査する前に、特定の結果が予想される前提条件を考えてください。 デバッガーで問題の原因を見つめていても、隠れているまたは不明な仮定が問題の特定を妨げることがあります。 考えられる前提条件の長いリストがあるかもしれません。 前提条件に挑戦するために自分自身に質問する必要がある質問をいくつか次に示します。
適切な API (つまり、適切なオブジェクト、関数、メソッド、またはプロパティ) を使用していますか? 使用している API は、思った動作を行わない可能性があります。 (デバッガーで API 呼び出しを調べた後、修正するには、正しい API を識別するためにドキュメントへの旅行が必要な場合があります)。
API を正しく使用していますか? おそらく、適切な API を使用しましたが、正しい方法で使用しませんでした。
コードに入力ミスが含まれていますか? 変数名の単純なスペルミスなど、一部の入力ミスは、特に変数を使用する前に宣言する必要のない言語を使用する場合に、見にくい場合があります。
コードに変更を加え、それが表示されている問題とは無関係であると想定しましたか?
実際に発生した内容とは異なる特定の値 (または特定の型の値) がオブジェクトまたは変数に含まれていることが予想されましたか?
コードの意図を知っていますか? 多くの場合、他のユーザーのコードをデバッグすることはより困難です。 コードでない場合は、コードを効果的にデバッグする前に、コードの動作を正確に学習するために時間を費やす必要がある可能性があります。
アドバイス
コードを記述するときは、小さく始めて、動作するコードから始めてください。 (ここでは、適切なサンプル コードが役立ちます)。場合によっては、達成しようとしているコア タスクを示す小さなコードから始めることで、大規模または複雑なコード セットを修正する方が簡単な場合があります。 その後、コードを段階的に変更または追加し、各時点でエラーをテストできます。
想定に疑問を投げかけることで、コードで問題を見つけるのにかかる時間を短縮できます。 また、問題の解決にかかる時間を短縮することもできます。
デバッグ モードでコードをステップ実行して、問題が発生した場所を見つけます
通常、アプリを実行すると、コードの実行後にのみエラーと正しくない結果が表示されます。 また、理由を伝えずに、プログラムが予期せず終了する場合もあります。
デバッガー内でアプリを実行すると(デバッグ モードとも呼ばれます)、デバッガーはプログラムの実行中に発生するすべてのことをアクティブに監視します。 また、アプリを任意の時点で一時停止して状態を確認し、コードを 1 行ずつステップ実行して、すべての詳細を確認することもできます。
Visual Studio では、F5
例外が発生しなかった場合は、コード内の問題を探す場所を適切に把握している可能性があります。 この手順では、デバッガーで ブレークポイント を使用して、コードをより慎重に調べる機会を得ることができます。 ブレークポイントは、信頼性の高いデバッグの最も基本的で不可欠な機能です。 ブレークポイントは、Visual Studio で実行中のコードを一時停止する場所を示します。そのため、コードが実行されるシーケンスの変数の値またはメモリの動作を確認できます。
Visual Studio では、コード行の横にある左余白をクリックすると、ブレークポイントをすばやく設定できます。 または、行にカーソルを置き、F9
これらの概念を説明するために、既にいくつかのバグがあるコード例を説明します。 C# を使用していますが、デバッグ機能は Visual Basic、C++、JavaScript、Python、およびその他のサポートされている言語に適用されます。 Visual Basic のサンプル コードも提供されていますが、スクリーンショットは C# にあります。
サンプル アプリを作成する (いくつかのバグあり)
次に、いくつかのバグがあるアプリケーションを作成します。
Visual Studio がインストールされていて、.NET デスクトップ開発 ワークロードがインストールされている必要があります。
Visual Studio をまだインストールしていない場合は、Visual Studio のダウンロード ページに移動して無料でインストールします。
ワークロードをインストールする必要があるが、既に Visual Studio がある場合は、[ツール]
[ツールと機能の取得] 選択します。 Visual Studio インストーラーが起動します。 [.NET デスクトップ開発] ワークロードを選んでから、[変更] を選びます。 Visual Studio を開きます。
スタート ウィンドウで、[新しいプロジェクト
作成] を選択します。 検索ボックス コンソール を入力し、C#選択するか、Visual Basic を言語として してから、.NET 用コンソール アプリ 選択します。 次にを選択し、次にを選びます。 プロジェクト名として ConsoleApp_FirstApp を入力し、[次へ]選択します。 別のプロジェクト名を使用する場合は、サンプル コードをコピーするときに、プロジェクト名と一致するように名前空間の値を変更する必要があります。
推奨されるターゲット フレームワークまたは .NET 8 を選択し、次に 、作成を選択します。
.NET 用の コンソール アプリ プロジェクト テンプレートが表示されない場合は、[ツール]>[ツールと機能の取得]に移動すると、Visual Studio インストーラーが開きます。 [.NET デスクトップ開発] ワークロードを選んでから、[変更] を選びます。
Visual Studio によってコンソール プロジェクトが作成され、右側のウィンドウ ソリューション エクスプローラー に表示されます。
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
は銀河型を格納するクラスの名前であることがわかります。 クラス名ではなく、実際の銀河の種類 ("スパイラル" など) を表示しようとしています。
アプリをデバッグする
アプリがまだ実行されている状態で、ブレークポイントを挿入します。
ループで、 メソッドの横を右クリックしてコンテキスト メニューを取得し、ポップアップ メニューから [ブレークポイント] [ブレークポイントの挿入] 選択します。 foreach (Galaxy theGalaxy in theGalaxies) { Console.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears + ", " + theGalaxy.GalaxyType); }
ブレークポイントを設定すると、左側の余白に赤い点が表示されます。
出力に問題がある場合は、デバッガーで出力を設定する上記のコードを参照してデバッグを開始します。
[デバッグ] ツールバーの [RestartApp]\(再起動\) ボタンを示す Restart
] ボタン (Ctrl + Shift + F5)。
設定したブレークポイントでアプリが一時停止します。 黄色の強調表示は、デバッガーが一時停止されている場所を示します (黄色のコード行はまだ実行されていません)。
右側の
GalaxyType
変数にカーソルを合わせ、次に、レンチアイコンの左側にあるtheGalaxy.GalaxyType
を展開してください。GalaxyType
にプロパティMyGType
が含まれており、プロパティ値がSpiral
に設定されていることがわかります。"スパイラル" は、実際にはコンソールに印刷する予定だった正しい値です。 そのため、アプリの実行中にこのコードの値にアクセスできることは良いスタートです。 このシナリオでは、正しくない API を使用しています。 デバッガーでコードを実行しているときにこれを修正できるかどうかを見てみましょう。
同じコードで、デバッグ中にカーソルを
theGalaxy.GalaxyType
の最後に置き、theGalaxy.GalaxyType.MyGType
に変更します。 編集はできますが、コード エディターにエラー (赤い波線) が表示されます。 (Visual Basic では、エラーは表示されず、コードのこのセクションは機能します)。F11 (デバッグ>ステップ イン またはデバッグ ツール バーの [ステップ イン] ボタン) を押して、現在のコード行を実行します。
F11 は、デバッガーを一度に 1 つのステートメントに進めてコードを実行します。 F10 (ステップ オーバー) も同様のコマンドであり、どちらもデバッガーの使用方法を学習するときに役立ちます。
デバッガーを進めようとすると、[ホット リロード] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。
[エディット コンティニュ] ダイアログ ボックスが表示され、編集をコンパイルできないことが示されます。
手記
Visual Basic サンプル コードをデバッグする場合は、デバッグ ツール バーの [アプリの再起動] ボタンを示す [再起動]
ボタン。
[ホット リロード] または [エディット コンティニュ] メッセージ ボックスで、[編集] を選びます。 エラー一覧の ウィンドウにエラー メッセージが表示されます。 このエラーは、
'object'
にMyGType
の定義が含まれていないことを示します。MyGType
プロパティを持つGType
型のオブジェクトを持つ各銀河を設定しても、デバッガーはtheGalaxy
オブジェクトをGType
型のオブジェクトとして認識しません。 どうなっているのですか。 あなたは銀河の種類を設定するコードを見直したいと思っています。 これを行うと、GType
クラスにMyGType
のプロパティがあることがわかりますが、何かが正しくありません。object
に関するエラーメッセージが手掛かりであることが判明しました。言語インタープリターに対して、型はGType
型のオブジェクトではなく、object
型のオブジェクトのように見えます。銀河型の設定に関連するコードを見ると、
GType
の代わりにGalaxy
クラスのGalaxyType
プロパティがobject
として指定されていることがわかります。public object GalaxyType { get; set; }
上記のコードを次のように変更します。
public GType GalaxyType { get; set; }
[デバッグ] ツール バーの [アプリの再起動] ボタンを示す
] ボタン (再起動アイコン 選択します。デバッグ ツール バーの [ Ctrl Shift F5 ) をクリックして、コードを再コンパイルして再起動します。これで、デバッガーが
Console.WriteLine
で一時停止すると、theGalaxy.GalaxyType.MyGType
上にマウス ポインターを合わせ、値が正しく設定されていることを確認できます。ブレークポイントを削除するには、左側の余白にあるブレークポイントの円をクリックして (または右クリックして [ブレークポイント
削除] を選択)、F 5 キー 押して続行します。 アプリが実行され、出力が表示されます。 見栄えは良いですが、1 つのことに気付きます。 あなたは、小さなマゼラン雲の銀河がコンソール出力に不規則な銀河として現れるのを期待しましたが、それは全く銀河の種類を示していません。
Tadpole 400, Spiral Pinwheel 25, Spiral Cartwheel, 500, Lenticular Small Magellanic Cloud .2, Andromeda 3, Spiral Maffei 1, Elliptical
switch
ステートメントの前 (Visual Basic のSelect
ステートメントの前) に、このコード行にブレークポイントを設定します。public GType(char type)
このコードは銀河の種類が設定されている場所であるため、詳しく見てみたいと思います。
再起動するには、デバッグ ツール バーの [再起動]
ボタン (Ctrl + Shift + F5 キー) を選びます。
デバッガーは、ブレークポイントを設定したコード行で一時停止します。
type
変数にカーソルを合わせます。S
の値が表示されます (文字コードの後)。I
の値に興味があるのは、それが不規則銀河型であることを知っているからです。F5
押し、もう一度 変数にカーソルを合わせます。 type
変数にI
の値が表示されるまで、この手順を繰り返します。次に、F11
押します ( デバッグ ステップ イン )。F11 キーを押し、'I' の値に対する
switch
ステートメントのコード行で停止するまで続けます (Visual Basic の場合はSelect
ステートメント)。 ここでは、入力ミスの結果として生じる明確な問題が表示されます。 コードは、MyGType
を不規則な銀河型として設定する場所に進む必要がありますが、代わりにデバッガーはこのコードを完全にスキップし、switch
ステートメント (Visual Basic のElse
ステートメント) のdefault
セクションで一時停止します。コードを見ると、
case 'l'
ステートメントに入力ミスが表示されます。 それはcase 'I'
であるべきです。case 'l'
のコードを選択し、case 'I'
に置き換えます。ブレークポイントを削除し、[再起動] ボタンを選択してアプリを再起動します。
バグが修正され、期待される出力が表示されます。
任意のキーを押してアプリを終了します。
概要
問題が発生した場合は、デバッガーと ステップ コマンド (F10、F11 など) を使用して、問題のあるコード領域を見つけます。
手記
問題が発生したコードの領域を特定することが困難な場合は、問題が発生する前に実行されるコードにブレークポイントを設定し、問題のマニフェストが表示されるまでステップ コマンドを使用します。 tracepoints を使用して、出力 ウィンドウにメッセージを記録することもできます。 ログに記録されたメッセージを調べて (まだログに記録されていないメッセージを確認します)、多くの場合、問題のあるコードの領域を特定できます。 このプロセスを何度か繰り返して絞り込む必要がある場合があります。
問題のあるコードの領域が見つかると、デバッガーを使用して調査します。 問題の原因を見つけるには、デバッガーでアプリを実行しているときに問題のコードを調べます。
変数 を検査し、変数に含める必要がある値の型が含まれているかどうかを確認します。 正しくない値が見つかると、正しくない値が設定された場所を確認します (値が設定された場所を見つけるには、デバッガーを再起動するか、呼び出し履歴を確認するか、またはその両方を確認する必要があります)。
アプリケーションが想定したコードを実行しているかどうかを確認します。 (たとえば、サンプル アプリケーションでは、
switch
ステートメントのコードで銀河の種類を [不規則] に設定することが想定されていましたが、入力ミスが原因でアプリによってコードがスキップされました)。
ヒント
バグを見つけるのに役立つデバッガーを使用します。 デバッグ ツールは、コードの意図がわかっている場合にのみ、"自動的に" バグを発見できます。 ツールは、開発者がその意図を表現している場合にのみ、コードの意図を知ることができます。 それを行う方法は、単体テストを書くことです。
次の手順
この記事では、いくつかの一般的なデバッグの概念について学習しました。 次に、デバッガーの詳細について学習を開始できます。