C#のデバッグとVS Code
C# コンソール アプリケーションのデバッグ (C# の概要、パート 6)
単純な C# コンソール アプリケーションを作成して実行する (C# の概要、パート 2)
-
VS Codeで
cnrl + shift + p
でコマンドパレットを開き、.NET: Generate Assets for Build and Debug
を選択するとデバッグ関係のjsonが生成される。 -
ブレークポイントを設定しただけでは、ブレークしない。ブレークポイントを有効化をする必要がある。
-
ブレークポイントには条件が付けられる。
- 条件が満たされるとブレークする。
-
ブレークポイントの種類
- 条件付き
- ヒットカウント
-
i == 2
の時だけブレークといった動作が可能。
-
- ログポイント
- 処理はブレークしない。
- ログを残していくだけ。
- ChatGPTにステップイン、ステップアウト、ステップオーバーを解説してもらう。
Visual Studio Code (VS Code) でのデバッグ時に使う「ステップイン」、「ステップアウト」、「ステップオーバー」の違いを以下に箇条書きで説明します。
ステップイン (Step Into)
- 機能: 次に実行されるコード行に移動し、関数呼び出しがある場合はその関数内部に入る。
- 使用目的: 関数の内部処理を詳しく調べたいとき。
- 詳細: 関数呼び出しがある行で実行すると、その関数の最初の行に移動する。
ステップアウト (Step Out)
- 機能: 現在の関数の実行を完了し、関数呼び出し元のコード行に戻る。
- 使用目的: 関数内部のデバッグが終わり、呼び出し元に戻りたいとき。
- 詳細: 現在の関数を最後まで実行し、呼び出し元の次の行に移動する。
ステップオーバー (Step Over)
- 機能: 次のコード行に移動し、関数呼び出しがあってもその内部には入らない。
- 使用目的: 関数の内部処理には関心がなく、次の行に進みたいとき。
- 詳細: 関数呼び出しがある行を実行するが、その関数の内部には入らずに次の行に進む。
まとめ
- ステップイン: 関数内部に入る → 詳細なデバッグ
- ステップアウト: 関数から抜ける → 呼び出し元に戻る
- ステップオーバー: 関数内部に入らず次の行に進む → 表面的なデバッグ
これらの機能を使い分けることで、効率的にデバッグが行えます。
-
Tips
- デバッグコンソールでは入力がサポートされていない。
- 入力が必要な場合は、
launch.json
のconsole
設定を、integratedTerminal
かexternalTerminal
にしないといけない。
- 入力が必要な場合は、
- デバッグコンソールでは入力がサポートされていない。
C# コンソール アプリケーションにロジックを追加する (C# の概要、パート 3)
-
try
を使う場合、catch
またはfinally
が必要
- 呼び出し履歴をCopilotに聞いてみる
「呼び出し履歴」は、プログラムの実行中に関数やメソッドがどの順序で呼び出されたかを記録するものです。主にデバッグやトラブルシューティングの際に役立ちます。呼び出し履歴を取得する方法はプログラミング言語や環境によって異なりますが、一般的なアプローチとして以下のものがあります。
-
スタックトレース:
- エラーが発生した際にスタックトレースを表示することで、呼び出し履歴を確認できます。スタックトレースには関数やメソッドの呼び出し順序が示されています。
-
ログファイル:
- ログファイルに呼び出し履歴を記録することで、プログラムの実行中に発生した関数やメソッドの呼び出しを追跡できます。
-
デバッガ:
- デバッガを使用してプログラムを実行する際に、呼び出し履歴を視覚的に確認できます。ブレークポイントを設定して関数やメソッドの呼び出しを追跡することができます。
具体的な実装方法は使用しているプログラミング言語や開発環境により異なりますので、詳細な手順はそれに合わせて調査してみてください。
- 例外はできるだけ発生した場所の近くでキャッチしよう。
try
{
Process1();
}
catch
// OverflowException を catch する。
{
Console.WriteLine("An exception has occurred");
}
Console.WriteLine("Exit program");
static void Process1()
{
try
{
WriteMessage();
}
catch (DivideByZeroException ex)
// DivideByZeroException は catch 済みなので実行されない。
{
Console.WriteLine($"Exception caught in Process1: {ex.Message}");
}
}
static void WriteMessage()
{
double float1 = 3000.0;
double float2 = 0.0;
int number1 = 3000;
int number2 = 0;
byte smallNumber;
try
{
Console.WriteLine(float1 / float2);
Console.WriteLine(number1 / number2);
}
catch (DivideByZeroException ex)
// DivideByZeroException を catch する。
// OverflowException は catch しない。
{
Console.WriteLine($"Exception caught in WriteMessage: {ex.Message}");
}
checked
{
smallNumber = (byte)number1;
}
}
- 複数の例外の種類をキャッチする必要がある場合は、複数の catch を指定する。
string[] inputValues = new string[] { "three", "9999999999", "0", "2" };
foreach (string inputValue in inputValues)
{
int numValue = 0;
try
{
numValue = int.Parse(inputValue);
}
catch (FormatException)
// inputValue == "three"
{
Console.WriteLine("Invalid readResult. Please enter a valid number.");
}
catch (OverflowException)
// inputValue == "9999999999"
{
Console.WriteLine("The number you entered is too large or too small.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
// https://learn.microsoft.com/ja-jp/training/modules/implement-exception-handling-c-sharp/7-exercise-catch-explicit-exception-types
-
checked
とunchecked
についてCopilotに聞く
「checked ステートメント」および「unchecked ステートメント」は、整数型の計算においてオーバーフローチェックを有効または無効にするための C# のキーワードです。これらのステートメントは、整数型の変換や演算が発生する際に、オーバーフローが検出されるかどうかを制御します。
以下に、それぞれのステートメントの動作について説明します。
-
checked ステートメント:
-
checked
ステートメントは、整数型の計算においてオーバーフローチェックを有効にします。 - 変換元の値が変換先の型の範囲内にある場合、変換は成功します。
- 範囲外の場合、
OverflowException
がスローされます。
-
-
unchecked ステートメント:
-
unchecked
ステートメントは、整数型の計算においてオーバーフローチェックを無効にします。 - 変換は常に成功し、オーバーフローが検出されない限り続行されます。
- 変換元の型が変換先の型より大きい場合、余分な最上位ビットは切り詰められ、結果は変換先の型の値として扱われます。
- 変換元の型が変換先の型より小さい場合、符号拡張またはゼロ拡張が行われ、結果は変換先の型の値として扱われます。
-
これらのステートメントを適切に使用することで、整数型の計算におけるオーバーフローの制御を行えます。
もしさらなる質問があればお知らせください!
- 符号拡張とゼロ拡張についてCopilotに聞く
符号拡張(sign extension)は、符号付きのデータをビット長の大きいデータに変換する際に、値を変えずにビットを補ってデータを拡張する操作です⁴。具体的には、次のようなケースで用いられます。
-
符号拡張:
- 符号付き整数値は、最上位ビットを「符号ビット」として予約しています。このビットが0なら正の数、1なら負の数とされます。
- ビット幅を広げる際に、元の最上位ビットを増える部分の全ビットに複写します。例えば8ビットを16ビットにする場合、上位8ビットの内容は、下位8ビットの最上位ビットに応じて0または0xffとなります²。
-
ゼロ拡張:
- ゼロ拡張は、2の補数表現を用いない(つまり自然数の)2進数計算をする場合に使います。
- 追加する桁数分だけ左側に0をつけるだけでゼロ拡張が完了します³。
このように、符号拡張とゼロ拡張は、整数のビット幅を変更する際に重要な操作です。どちらも正確な計算を行うために必要な手法です。もしさらなる質問があればお知らせください!
- C# での例外のキャッチに関して推奨される方法はどれですか?
- コードが復旧方法を認識している例外のみをキャッチします。
- 正解です。 推奨される方法は、コードが復旧方法を認識している例外のみをキャッチすることです。
C# コンソール アプリケーションで変数データを操作する (C# の概要、パート 4)
- Copilotから
例外をスローする際に避けるべきことについて、以下の要点をまとめました。
-
プログラムフローの乱用回避:
- 例外はエラー状態の報告と処理のためにのみ使用し、通常の実行フローを変更するためには使用しない。
-
戻り値としての例外回避:
- 例外をスローする代わりに、戻り値やパラメーターとして返さない。
-
特定例外のスロー回避:
-
System.Exception
、System.SystemException
、System.NullReferenceException
、System.IndexOutOfRangeException
などの基本的な例外は意図的にスローしない。
-
-
デバッグ専用例外の回避:
- デバッグモード専用でスローされる例外を作成せず、ランタイムエラーの特定には
Debug.Assert
を使用する。 - つまり、開発フェーズでスローできるのに、本番フェーズでスローできない例外は、スローしてはだめ。
- デバッグモード専用でスローされる例外を作成せず、ランタイムエラーの特定には
これらのガイドラインに従うことで、例外を適切に使用し、プログラムの安定性とメンテナンス性を向上させることができます。もし他に質問があればお知らせください。
例外を作成しスローする際の重要なポイントを以下にまとめます。
-
例外の種類を選ぶ:
- 例外の目的にできるだけ近い種類を選びます。具体的なエラーを反映するカスタム例外クラスを作成することもあります。
-
例外オブジェクトの構築:
- 例外派生クラスのインスタンスを作成し、プロパティを構成します。
- エラーメッセージや詳細情報を提供して、ユーザーが問題を修正できるようにします。
これらのポイントを守ることで、適切な例外処理を実装できます。他にも質問があればお知らせください!
-
Debug.Assert
メソッドとは?
Debug.Assert
メソッドは、開発中のロジック エラーを検出するためのツールです。通常、デバッグ ビルドでのみ機能します。このメソッドは、発生してはならない条件を確認する目的で使います。プログラムの正常な実行中に発生する可能性のあるエラーを処理する目的では例外を使うようにします。
Debug.Assert
メソッドは、2つのパラメーターを受け取ります。
- 確認するブール条件
- 条件が
false
の場合に表示する省略可能な文字列メッセージ
例外をスローする代わりに Debug.Assert
を使うことで、コードの通常の実行中に生じた例外的な状況を処理する方法を提供します。もしさらなる質問があればお知らせください!
「debug」と「test」は、プログラム開発において異なる目的で使用される用語です。
-
Debug (デバッグ):
- デバッグは、プログラムのバグ(エラー)を特定して修正する作業です。
- プログラムが意図通りに動作しない場合、デバッグを行います。
- デバッグの手法には、ログの出力、ブレークポイントの設定、ステップ実行などがあります。
-
Test (テスト):
- テストは、プログラムが正しく動作するかどうかを確認する作業です。
- テストは、プログラムの品質を保証するために行います。
- テストの種類には、単体テスト、結合テスト、受け入れテストなどがあります。
簡潔に言えば、デバッグはバグを修正し、テストはプログラムの品質を確認する作業です。どちらもプログラム開発において重要なステップです。もしさらなる質問があればお知らせください!