私の「インターフェイス コードと関数コードを分離する方法 (Delphi/VCL に基づく)」を読んだ後、誰かがサーバー側クラスのエラーを処理する方法についての質問に言及しました。
関数ベースの構造では、通常、関数の戻り値を使用して、関数が正常に実行されたかどうかを示し、エラーの種類などの情報を提供します。したがって、次の形式のコードが存在します。
RetVal := SomeFunctionToOpenFile();
RetVal = E_SUCCESSED の場合
...
それ以外の場合、RetVal = E_FILENOTFOUND の場合
...
それ以外の場合、RetVal = E_FILEFORMATERR の場合
...
そうでなければ
...
エラー コードを返すメソッドを使用するのは非常に一般的ですが、このようなメソッドの使用には次の 2 つの問題があります。
1. 長く複雑な分岐構造(多数の if 文や case 文)が生成され、制御プロセスが複雑になります。
2. 処理されていないエラーが存在する可能性があります(関数呼び出し側が戻り値を決定していない場合)
例外は、エラー処理のためのオブジェクト指向のソリューションです。エラーを報告することはできますが、知っておく必要があるのは、エラーが原因で例外が発生するのではなく、単に raise が使用されているために例外が発生するということです。
Object Pascal では、例外をスローするために、発生した予約語が使用されます。いつでも (エラーが発生しなくても)、raise によって例外が発生します。
例外が発生すると、コードが例外が発生した時点からすぐに戻るため、以下の機密性の高いコードが実行されるのを防ぐことができます。例外をスローする関数自体については、例外を通じて関数から戻ることと、関数から通常に戻る (関数の最後まで実行するか、Exit を実行する) ことに違いはありません。違いは、呼び出し側で、例外を介して戻った後、呼び出し側の try...Except ブロック (存在する場合) によって実行権限が取得されることです。呼び出し元に Try...Except ブロックがない場合、後続のステートメントは実行を続行せず、例外を処理できる Try...Except ブロックが見つかるまで上位レベルの呼び出し元に戻ります。例外が処理された後、try...Except ブロックの後のステートメントは引き続き実行され、制御は例外を処理する層に残されます。例外ハンドラーは、例外の処理が十分に完了していないと判断した場合、上位レベルの呼び出し元に処理を継続させる必要があり、(単純な raise; を使用して) 例外を再スローし、上位レベルの呼び出し元に制御を移すことができます。 。
Try...Except ブロックがまったくプリセットされていない場合、最後の例外は、プログラム全体をカプセル化する VCL の最も外側の Try...Except ブロックによってキャッチされます。
したがって、未処理の例外は存在しません。つまり、未処理のエラーは存在しません (ただし、エラーと例外は同等ではありません)。これは、エラー コードを返すメソッドを使用する場合に比べて、例外メカニズムの利点でもあります。さらに、例外がスローされた後、制御プロセスの方向は非常に明確であり、プロセスが制御を失うことはありません。
例外がどのように機能するかを示す例として、特定の形式でファイルを開きたいとします。
最初に 2 つの例外クラス (Exception から継承) を定義します。
EFileNotFound = クラス(例外);
EFileFormatErr = クラス(例外);
Form1 にボタンがあり、ボタンを押すとファイルが開くとします。
手順 TForm1.Button1Click(送信者: TObject);
始める
試す
ToOpenFile();
を除外する
EFileNotFound で行う
ShowMessage('申し訳ありません、ファイルが見つかりません');
onEFileFormatErr を実行します
ShowMessage('申し訳ありませんが、必要なファイルではありません');
E:例外実行
ShowMessage(E.Message);
終わり;
終わり;
ファイルを開く関数:
プロシージャToOpenFile;
varRetVal:整数;
始める
//openfile へのコード
RetVal := -1; //オープンに失敗しました。
RetVal = 0 の場合 // 成功
出口
それ以外の場合、RetVal = -1 の場合
Raise EFileNotFound.Create('ファイルが見つかりません')
それ以外の場合、RetVal = -2 の場合
Raise EFileFormatErr.Create('ファイル形式エラー')
else //その他のエラー
Raise Exception.Create('不明なエラー');
終わり;
プログラムでは、TForm1.Button1Click が ToOpenFile を呼び出し、ToOpenFile によってスローされる可能性のある例外の処理を除き、try... をプリセットします。もちろん、TForm1.Button1Click の例外処理コードも簡略化することができます。
プロシージャ TForm1.Button1Click(送信者: TObject);
始める
試す
ToOpenFile();
を除外する
ShowMessage('ファイルを開くのに失敗しました');
終わり;
終わり;
例外を使用すると、エラー コードを返すメソッドを使用する際の問題が解決されます。 もちろん、例外を使用するとコストがかかります。例外はプログラムの負担を増大させるため、例外を乱用することはお勧めできません。数回の試行 (例外を除く) を書くのと、何千回の試行 (例外を除く) を書くことの間には大きな違いがあります。 Charlie Calverts の言葉を借りれば、「便利だと思われる場合は try...excect ブロックを使用する必要があります。ただし、この手法にあまり興奮しないようにしてください。」
さらに、Object Pascal では、独自の try...finally 構造が導入されています。前に、例外を通じて関数から戻ることと、関数から通常に戻ることの間に違いはないと言いました。したがって、関数内のスタック内のローカル オブジェクトは自動的に解放されますが、ヒープ内のオブジェクトは自動的に解放されません。ただし、Object Pascal のオブジェクト モデルは、スタックではなくヒープに存在する参照に基づいています。したがって、場合によっては、例外を通じて関数から戻る前に、いくつかのローカル オブジェクト リソースをクリーンアップする必要があります。試してみてください...ついにこの問題が解決されました。
上記の ToOpenFile コードを書き直しました。今回は ToOpenFile プロセス中にいくつかのリソースを使用し、例外が発生した (または発生しなかった) 後、関数から戻る前にこれらのリソースを解放します。
プロシージャToOpenFile;
varRetVal: 整数。
ストリーム: TStream;
始める
//openfile へのコード
ストリーム := TStream.Create;
RetVal := -1; //オープンに失敗しました。
試す
RetVal = 0 の場合 // 成功
出口
それ以外の場合、RetVal = -1 の場合
Raise EFileNotFound.Create('ファイルが見つかりません')
それ以外の場合、RetVal = -2 の場合
Raise EFileFormatErr.Create('ファイル形式エラー')
else //その他のエラー
Raise Exception.Create('不明なエラー');
ついに
ストリーム。無料。
終わり;
終わり;
上記のコードをステップ実行すると、RetVal の値が 0 の場合でも、Exit の実行後、finally のコードが引き続き実行され、関数から戻ることがわかります。これにより、ローカル リソースが正しく解放されることが保証されます。
try...excel と try...finally は目的や使用シーンが異なるため、混同する初心者も少なくありません。以下は作成者の個人的な知識です。 try...Except は通常、呼び出された関数によってスローされた例外を捕捉し、処理するために呼び出し元によって使用されます。また、try...finally は通常、リソースのクリーンアップ作業を実行するために例外をスローする関数に使用されます。
オブジェクト指向プログラミングでは、「例外」と呼ばれるエラー処理ソリューションが提供されます。賢く使用すると、作業に利益をもたらし、作成するコードの品質を大幅に向上させることができます。
ニクロソフト ([email protected]) 2001.7.25
元のソース: Sunistudio ドキュメント (http://www.sunistudio.com/asp/sunidoc.asp)