新しいプログラマーに例外処理を教える方法は?[閉まっている]


21

例外処理をプログラマーに教える方法を教えてください。他のすべてのこと-データ構造、ASP.NET、WinForms、WPF、WCF-を簡単に教えられます。名前を付ければ、すべてが簡単に教えられます。

例外処理では、try-catch-finallyを教えることは、例外処理の構文的な性質にすぎません。

ただし、教えるべきことは-コードのどの部分をtryブロックに入れますか?catchブロックで何をしますか?

例で説明しましょう。

Windows Formsプロジェクト(小さなユーティリティ)で作業しており、3つの異なるプロジェクトで以下のように設計しました。

  1. UILayer
  2. BusinessLayer
  3. DataLayer

DataLayerで例外(XDocumentをロードすると例外がスローされると言います)が発生した場合(UILayerがBusinessLayerを呼び出し、BusinessLayerがDataLayerを呼び出します)、次のようにしますか?

//In DataLayer
try {
    XDocument xd_XmlDocument = XDocument.Load("systems.xml");
} 
catch(Exception ex)
{
    throw ex;
}

BusinessLayerで再びスローされ、ログファイルに書き込むUILayerでキャッチされるのはどれですか?

これはあなたが例外処理をどのように行っているのですか?


15
あなたがいる場合されたことをやろうとして、あなたはキャッチ(例外例){スローEXにしたくありません。}-代わりに{throw; }
スティーブンエバーズ

4
finallyブロックを忘れないでください。
クリス

1
タグで言語を指定する必要があります。例外のほとんどの実装で一般的なものよりも詳細になり、ブロック外のものを無視しています。たとえば、C ++では、例外処理の最も重要な部分は、例外セーフプログラムの作成方法を知ることです。
デビッドソーンリー


「例外」をキャッチするのは悪い考えであることをご理解ください。特定の例外をキャッチし、それに応じて(例外をスローするだけでなく)処理するには、ネストされたcatchブロックが必要です。
-minusSeven

回答:


29

例外処理を説明するには、その背後にある概念を説明します。エラーが頻繁に発生するコードは、そのエラーを適切に処理する方法を知りません。 適切に処理する方法を知っているコードは、その関数を呼び出した関数であるか、呼び出しスタックのさらに上にある可能性があります。

例外をスローする可能性のあるルーチンを呼び出すルーチンを作成するときに、そのエラーを正しく処理する方法がわかっている場合は、呼び出しをtryブロックに入れ、エラー処理コードをcatchブロックに入れます。そうでない場合は、そのままにして、呼び出しスタックの上の何かがエラーを処理できるようにします。

「catch ex、throw ex」と言うの、実際には何も処理しないため、例外処理を行うのに良い方法ではありません。さらに、言語の例外モデルがどのように機能するかに応じて、問題のデバッグに使用できたスタックトレース情報をクリアすると、実際に有害になる可能性があります。例外の処理方法を知っているルーチンに到達するまで、例外を呼び出しスタックに伝播させてください。


4
「それは実際には何も処理しないので、...」のために1、そう頻繁に捕捉手段は取り扱いを考えると、あなたが問題を修復するために何かをしない場合、それはだ気付いていない例外処理に新たな人ではない例外処理、ただコードが肥大化します。
ジミー・ホッファ

13

ほとんどの場合と同様に、一見単純なソリューション(Cスタイルの戻りコードとerrno)がそれほどうまく機能しない理由を示すまで、例外と例外処理は新しいプログラマーにとって問題を探す解決策のように思われます。私は、問題の動機付けをして、それを文脈に入れることから始めます。リターンコードまたはグローバル/静的変数を使用してエラー処理を行う方法を示します。次に、それがうまく機能しない理由の例を示します。次に、とだけにして、例外を導入し、彼らはアウトオブバンドシグナリングの形だと説明していることを全体のポイントは、あなたが無視した場合、例外が誰かにコールスタックまで責任を転嫁しているデフォルトの動作ということが誰であるかをすることができます扱う。

結論:Cでエラー処理がどのように行われたかを示すことにより、生徒は例外が実際に何のためにあるのかを理解し、本当に処理できない例外をキャッチすることが基本的に暗黒時代に物事が行われた方法をシミュレートするのです。


2
従来のCスタイルのリターンコードとエラー番号でそれらを導き、それが不十分に機能することを示す教育実践のために+1。したがって、それがどのように機能するかを教えることは素晴らしいことです。
カニーニ

3
@Kanini:一般的に、比較的新しい/高レベルの構成要素のほとんどは、問題を探すための解決策のように思え、解決する問題とその発明の理由を理解していなければ、簡単に間違っていると思います。
-dsimcha

私はそれが例外なしに行われることになるかを示すことは良くあることに同意したが、その後、例外を使用する際に説明するの負担とするとき(すべてではない状況が例外的であるため)他のテクニクスを使用するには来る
マシューM.

@Matthieu:そうです。しかし、例外が真空で学習するのではなく、例外が解決しようとする歴史的な問題を理解している場合、例外以外の状況でそれらを使用するのは愚かであることが明らかになります。
dsimcha

そう、だからあなたは私の+1を手に入れた。私はちょうどあなたの答えは、「別のメカニズムを使用することはありません」と解釈される可能性を感じた:)
マシューM.

5

まず、例外の設計ガイドラインから始めましょう。DO、DO NOT、AVOIDが含まれています。また、理由も示します。

あなたの例の場合、revelventセクションはWrapping Exceptionsです

そして、それがこのように書かれることを期待するでしょう。特定の例外をキャッチし、より意味のあるメッセージが伝播されるように情報を追加しようとすることに注意してください。また、ロギングの目的で内部例外が維持されていることに注意してください

//In DataLayer

try
{
XDocument xd_XmlDocument = XDocument.Load("systems.xml");
}
catch(FileNotFoundException ex)
{
        throw new TransactionFileMissingException(
                     "Cannot Access System Information",ex);
}

UPDATE Kaniniは、この例外ブロックをデータレイヤーに入れるのが正しいのか、またはファイルのチェックをビジネスレイヤーで利用できるようにするのが正しいのかを尋ねます。

まず、例外をラッピングする理由は次のとおりです。

下位層の例外が上位層の操作のコンテキストで意味をなさない場合は、下位層からスローされた特定の例外をより適切な例外にラップすることを検討してください。

したがって、ファイルについて上位層が知っている必要があると感じる場合、データ層は次のようになります。

//In DataLayer

XDocument xd_XmlDocument = XDocument.Load("systems.xml");

キャッチしようとしない。

個人的には、データレイヤーがアセンブリリソースであるデフォルトのsystems.xmlを使用するような便利なことを実行できない限り、何もしないか、例外をラップすることは、どのメソッドとどのファイルが問題であるかをログに記録するので良い方法だと思います。(throw exこの場合、または優先される場合でも、throw値は追加されません)。これは、特定されると、問題を迅速に修正できることを意味します。

また、この特定の例には、XDocument.Loadが4つの例外をスローする可能性があるという点で、次の問題もあります。

  • ArgumentNullException
  • SecurityException
  • FileNotFoundException
  • UriFormatException

次のコードがFileNotFoundExceptionをスローしないことを安全に保証することはできません。単に、存在チェックを行ったときに存在し、ロードを行ったときに消失する可能性があるからです。それをビジネスレイヤーで使用できるようにすることは役に立ちません。

 if (File.Exists("systems.xml")) 
     XDocument.Load("systems.xml");

SecurityExceptionはさらに悪化します。これは、別のプロセスグラブが排他的なファイルロックを持っている場合にスローされる他の理由の中で、File.CanIOpenThis()メソッドがないため、読み取りのために開いてみるまでエラーを受け取らないからです。そして、そのような方法が存在する場合、File.Existsの場合と同じ問題がまだあります。


修正:ありがとう!しかし、この例外ブロックをデータレイヤーに持つことは正しいのでしょうか?ファイルが利用可能かどうかをビジネス層にチェックすること全体を行う必要がありますか?それ以外の場合、コードの記述方法に同意します。
カニーニ

修正:私の母国語では、カニーニはコンピューターを意味し、カニは果物を意味します;
カニーニ

私はあなたが私のエラーにあまり動揺していないと言うことができますが、私は非常に残念であり、私はそれを修正しました。
コンラッドフリックス

1
修正:動揺しましたか?どういたしまして。おもしろい。私はとにかく奇妙な形のために多分除く外に果物を似ていない、ので、私は主に彼にこのアウトを指摘ので、私の弟は笑って停止していません...
Kanini

4

ロールプレイをしましょう。(これは冗談の投稿ではありません)

コールチェーンを実行するワークショップを行う必要があります。各人はオブジェクトです。初心者と「ゲーム」を理解している人が必要です。

ファイルIOのような本当に単純な問題を使用します。gui-> model-> file_io

ファイルリーダーである人は、次のものを伝える必要があります。

まず、リターンコードを使用して実行します。(付箋紙を使用しますか?)

インタラクションがただ「コードの言うこと」である場合、例外が例外的であることを人々に認識させることができます。

リターンコードについては、ポストイットノートを渡します。

例外については、手を空中に投げて、問題が何であるかを言ってください。

次に、「キャッチx、スローx」を実行させ、GUIが「モデルに例外があった」という診断がさらに悪いことを確認します。

他の人との相互作用をよく理解しているので、これはあなたが持っている人を訓練するのに役立つと思います。


ロールプレイのアイデアについては+1。以前考えたことはありませんでした。ロールプレイを通じてプログラミング教育を行うことができると考えた人はいませんか?
カニーニ

1

たとえば、クラスの子/親の関係を理解するために最初に必要な例外を理解すると思います。子が親から機能を継承できることを理解している場合、子が問題を抱えている場合、それを処理できないということを初級レベルで理解できる可能性があります。それと。

例外の処理方法を知っている場所で終わるまで、これは連鎖関係になります。

そして最後に行く限り、これは些細な部分です...問題が発生した場合、プログラムが致命的に終了しないように何かを処理する必要があり、その例外が処理された後、try catchに関係なく常に実行されるfinallyブロックがあります。

これの良い例は、ネットワークの場合です:

  • 接続します
  • 接続は問題ないので使用します
  • 終了したら、リソースを閉じて解放します

または例外の場合:

  • 接続する
  • 何かが処理する例外が発生する
  • どの時点で接続と関連リソースを解放します

1

例外処理が非常に優れている初心者にアプリケーションを提供します。どこかに例外をスローし、ログを使用してデバッグできるようにします。例外の伝播を追跡することで、彼らはそれをデバッグできるはずです。この演習を3回または4回行います。次に、コードからすべての例外処理を削除し、同じ例外を追跡できるようにします。

例外処理コードへの感謝は即座に感謝されると信じています。


計画のようだ。インターネット(sourceforge.netなど)で利用可能なサンプルコードはありますか?
カニーニ

0

IMO、例外処理とフロー制御ステートメントは基本的に同じであると考える必要があります。それらを使用して、現在の状態に基づいてプログラムのフローを制御します。違いは、例外処理はエラー(または例外)が発生したときにのみ反応することです。


@denny:「例外処理はエラー(または例外)が発生した場合にのみ反応する」ことに同意しますが、「例外処理とフロー制御ステートメントは基本的に同じ」というステートメントについてはよくわかりません。私はそこに敬意を表しません。catchブロックは、確か​​にその条件下ですべきことをします。ただし、tryブロックはフローや制御に関するものではありません。最後のブロックは、やはりフローや制御に関するものではありません。たぶん、あなたの答えを誤解したかもしれませんが、私と他の人のために明確にすることができますか?
カニーニ

0

おそらく新しいプログラマーには役に立たないでしょうが、関数型プログラミングでモナドを使い始めたら、例外の概念をよりよく理解できることがわかりました。モナドは、データフローの一部を「隠す」ための便利な抽象化を提供するため、データがプログラムに出入りするすべての「チャネル」を考慮することを強制します。

関数にはさまざまなタイプの出力があり、例外は関数からの優先度の高い戻り値のようなものであるという考えは、か​​なりきれいです。

心は、ほとんどの言語(実装の詳細)で例外がどのように機能するかではなく、抽象的な意味で、それが起こっていることを理解しています。


0

猿がキーボードを使用しているふりをする

私は、猿がキーボードに座ってこのアプリケーションを使用するふりをするコードを書いているときに、みんなに言っていました。

これは、あらゆる種類のことを予測する方法を彼らに教えました:

  • 欠落データ
  • 不足しているファイル
  • 数字を期待するときのアルファベット文字
  • ゼロ除算

猿が鍵を叩くだけで、うまくやるのではなく、やりたいことを何でもするという言葉の絵だったと思います。それは私のために働いた。


サル?私はあなたのビジネスユーザーがそれを聞いたことがないと思う;
カニーニ

@Kanini-いいですね。それは私の海兵隊時代でした。エラートラップに関しては、ボックスの外側で考えるようにしたかっただけです。エラートラップと言いましたか...例外処理を意味します。
マイケルライリー-別名ガニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.