演習 - C# コンソール アプリケーションで例外をスローしてキャッチする
この演習では、トップレベルのステートメントで try コード ブロックと catch 句を作成し、MakeChange メソッドで例外を作成してスローし、例外オブジェクトを使用して catch コード ブロックを完了します。 この演習では、次のタスクを実行します。
- トップレベルのステートメントの更新す: トップレベルのステートメントに
try-catchパターンを実装します。tryコード ブロックには、MakeChangeへの呼び出しが含まれます。 -
MakeChangeメソッドの更新: "Insufficient till" および "Underpayment" の問題に対する例外を作成してスローします。 - スローされた例外のプロパティを使用するように
catchコード ブロックを更新します。 - 検証テスト: この演習で開発したコードの検証テストを行います。
トップレベルのステートメントに try-catch パターンを追加する
このタスクでは、MakeChange メソッドの呼び出しを try ステートメント内に囲み、対応する catch 句を作成します。
Visual Studio Code エディターで Program.cs ファイルが開かれていることを確認します。
次のコード行を見つけます。
// MakeChange manages the transaction and updates the till string transactionMessage = MakeChange(itemCost, cashTill, paymentTwenties, paymentTens, paymentFives, paymentOnes); // Backup Calculation - each transaction adds current "itemCost" to the till if (transactionMessage == "transaction succeeded") { Console.WriteLine($"Transaction successfully completed."); registerCheckTillTotal += itemCost; } else { Console.WriteLine($"Transaction unsuccessful: {transactionMessage}"); }このコードの目的について考えてみましょう。
MakeChangeは、文字列値を返すことに注意してください。 戻り値は、transactionMessageという名前の変数に割り当てられます。transactionMessageが "transaction succeeded" と等しい場合、購入された商品の代金がregisterCheckTillTotalに追加されます。 変数registerCheckTillTotalは、MakeChangeメソッドによって計算されたレジ残高を確認するために使用されます。MakeChangeメソッドの呼び出しをtryステートメント コード ブロックで囲むには、コードを次のように更新します。try { // MakeChange manages the transaction and updates the till string transactionMessage = MakeChange(itemCost, cashTill, paymentTwenties, paymentTens, paymentFives, paymentOnes); }catchステートメント コード ブロックの後に次のtry句を追加します。catch { }例外を作成してスローしたら、
catch句の開発は完了です。
MakeChange メソッドで例外を作成してスローする
このタスクでは、MakeChange を更新して、トランザクションを完了できない場合にカスタム例外を作成してスローします。
MakeChange メソッドには、例外を発生させる必要がある次の 2 つの問題が含まれています。
Underpayment 問題: この問題は、顧客が商品代金よりも少ない金額を支払った場合に発生します。 顧客が十分な金額を支払わなかった場合、
MakeChangeでは例外をスローする必要があります。Insufficient till 問題: この問題は、おつりに必要な紙幣がレジにない場合に発生します。 レジにおつりがない場合、
MakeChangeでは例外をスローする必要があります。
下にスクロールして
MakeChangeメソッドに移動します。次のコード行を見つけます。
if (changeNeeded < 0) transactionMessage = "Not enough money provided.";このコードで対処しようとしている問題について考えてみましょう。
changeNeededが 0 未満の場合、顧客は、購入しようとしている商品の購入価格に充当する十分な金額を支払っていません。 購入価格と顧客が支払った金額は、MakeChangeメソッドのパラメーターです。 顧客が十分な金額を支払わない場合、このメソッドはトランザクションを完了できません。 つまり、操作は失敗します。これらの条件に一致すると思われる例外の種類が 2 つあります。
-
InvalidOperationException:InvalidOperationException例外は、メソッドの動作条件が特定のメソッド呼び出しの正常な完了をサポートしていない場合にのみスローする必要があります。 この場合、このメソッドに提供されたパラメーターによって動作条件が確立されます。 -
ArgumentOutOfRangeException-ArgumentOutOfRangeException例外は、引数の値が、呼び出されたメソッドによって定義された値の許容範囲外にある場合にのみスローする必要があります。 この場合、支払われた金額は商品代金よりも多くなければなりません。
どちらの種類の例外も機能する可能性はありますが、このアプリケーションのコンテキストでは、わずかですが、
InvalidOperationExceptionの方がより適しています。-
コードを次のように更新します。
if (changeNeeded < 0) throw new InvalidOperationException("InvalidOperationException: Not enough money provided to complete the transaction.");下にスクロールして、次のコード行を見つけます。
if (changeNeeded > 0) transactionMessage = "Can't make change. Do you have anything smaller?";このコードで対処しようとしている問題について考えてみましょう。
おつりを準備する
changeNeededループの後でwhileが 0 より大きい場合、レジには、おつりに使用できる紙幣が不足しています。 おつりに必要な紙幣がレジにない場合、メソッドはトランザクションを完了できません。 つまり、操作は失敗します。例外を作成するには、
InvalidOperationException例外を使用する必要があります。コードを次のように更新します。
if (changeNeeded > 0) throw new InvalidOperationException("InvalidOperationException: The till is unable to make the correct change.");
catch コード ブロックを完了する
このタスクでは、catch 句を更新して、特定の例外の種類をキャッチします。
MakeChangeメソッドより上にスクロールし、次のコードを見つけます。catch { }MakeChangeメソッドでスローされた例外の種類をキャッチするには、コードを次のように更新します。catch (InvalidOperationException e) { Console.WriteLine($"Could not complete transaction: {e.Message}"); }InvalidOperationExceptionでスローされたMakeChange例外オブジェクトはキャッチされますが、他の例外の種類はキャッチされません。 他の例外の種類を処理する準備ができていないため、それらがコール スタックの下位でキャッチされるようにすることが重要です。MakeChange内に他の例外の種類が想定されることに気付いた場合は、さらにcatch句を追加できます。[ファイル] メニューを使用して更新を保存します。
MakeChange メソッドを "string" から "void" に変換し、例外プロパティにアクセスする
このタスクでは、MakeChange を void 型になるように更新し、例外プロパティを使用して問題の詳細をユーザーに伝えます。
MakeChangeメソッドの一番上までスクロールします。MakeChangeメソッドをstring型からvoid型に変換するには、コードを次のように更新します。static void MakeChange(int cost, int[] cashTill, int twenties, int tens = 0, int fives = 0, int ones = 0)次の変数宣言を削除します。
string transactionMessage = "";MakeChangeメソッドの一番下までスクロールします。次のコードを削除します。
if (transactionMessage == "") transactionMessage = "transaction succeeded"; return transactionMessage;トップレベルのステートメントまで上にスクロールし、
tryコード ブロックを見つけます。tryコード ブロックを次のように更新します。try { // MakeChange manages the transaction and updates the till MakeChange(itemCost, cashTill, paymentTwenties, paymentTens, paymentFives, paymentOnes); Console.WriteLine($"Transaction successfully completed."); registerCheckTillTotal += itemCost; }次のコード行を見つけて削除します。
// Backup Calculation - each transaction adds current "itemCost" to the till if (transactionMessage == "transaction succeeded") { Console.WriteLine($"Transaction successfully completed."); registerCheckTillTotal += itemCost; } else { Console.WriteLine($"Transaction unsuccessful: {transactionMessage}"); }tryおよびcatchコード ブロックは、トランザクションの "成功" および "失敗" のメッセージをユーザーに伝えるようになりました。 問題については、例外のMessageプロパティで説明されるため、1 つのConsole.WriteLine()ステートメントだけで両方の問題に対処します。 これらの更新後、コードは読みやすくなり、保守も容易になります。[ファイル] メニューを使用して更新を保存します。
作業を確認
このタスクでは、アプリケーションを実行し、更新されたコードが意図したとおりに動作することを確認します。
上にスクロールして、トップレベルのステートメントで
whileループを見つけます。このループは、トランザクションを反復するために使用されます。
whileループの開始行の数行前にある次のコードを見つけます。int transactions = 10;トランザクションの回数を次のように
40に更新します。int transactions = 40;whileループ内で次のコード行を見つけます。int itemCost = valueGenerator.Next(2, 20);itemCost乱数ジェネレーターを次のように更新します。int itemCost = valueGenerator.Next(2, 50);顧客が購入する商品には、この価格範囲の方がより適しています。
[ファイル] メニューを使用して更新を保存します。
[実行] メニューで、[デバッグの開始] を選択します。
[ターミナル] パネルで出力を確認します。
次の 2 つの例外の種類に関連付けられているメッセージが表示されていることを確認します。
トランザクション レポートには、次の "Could not complete transaction" というメッセージが含まれているはずです。
Customer is making a $42 purchase Using 2 twenty dollar bills Using 0 ten dollar bills Using 0 five dollar bills Using 0 one dollar bills Could not complete transaction: InvalidOperationException: Not enough money provided to complete the transaction.Customer is making a $23 purchase Using 2 twenty dollar bills Using 0 ten dollar bills Using 0 five dollar bills Using 1 one dollar bills Cashier prepares the following change: A five A five A one A one Could not complete transaction: InvalidOperationException: The till is unable to make change for the cash provided.
これで、コード ロジックの問題を修正するためにキャッシュ レジスタ アプリケーションをデバッグし、適切な例外処理手法を使用するようにアプリケーションを更新しました。
注
報告された出力は、レジの資金のバランスが取れなくなったことを示しています。 コードには追加のロジック バグがあります。 Visual Studio Code でのデバッグのスキルを実際に試したい場合は、チャレンジ プロジェクト モジュールを利用できます。