61

FinallyinTry .. Catchは、try catch ブロックの実行の任意の部分の後に常に実行されることがわかります。

Finallyセクションをスキップして、try catch ブロックの外側で実行するのと何か違いはありますか?

例 1、Try ... Catch ... 最後に ... End Try

    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    Finally
        'Do cleanup
    End Try

例 2、Try ... Catch ... End Try ... 最終的に外部で実行

    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    End Try
    'Do cleanup
4

14 に答える 14

83

はい、違います。最終的には常に実行されます (プログラムのクラッシュを除く)。関数が try catch ブロック内で終了した場合、または try または catch のいずれかで別のエラーがスローされた場合でも、finally は引き続き実行されます。finally ステートメントを使用しないと、その機能は得られません。

于 2009-07-21T11:39:02.833 に答える
16

4 つのラジオ ボタンを含むコード:

  • TRY で返品
  • CATCHで返す
  • CATCHを投げる
  • フィニッシュキャッチ

    private void checkFinally()
    {
        try
        {
            doFinally();
        }
        catch
        {
            Console.WriteLine(" Breaking news: a crash occured. ");
        }
    }
    
    private void doFinally()
    {
        Console.WriteLine(" ");
        Console.Write("Here goes: " 
            + (radioReturnInTry.Checked ? "2. Return in try: " 
                    : (radioReturnInCatch.Checked? "3. Retrun in catch: "
                        : (radioThrowInCatch.Checked? "4. Throw in catch: "
                            : "1. Continue in catch: "))) );
        try
        {
            if (radioReturnInTry.Checked)
            {
                Console.Write(" Returning in try. ");
                return;
            }
            Console.Write(" Throwing up in try.  ");
            throw new Exception("check your checkbox.");
        }
        catch (Exception ex)
        {
            Console.Write(" ...caughtcha! ");
            if (radioReturnInCatch.Checked)
            {
                Console.Write("Returning in catch. ");
                return;
            }
            if (radioThrowInCatch.Checked)
            {
                Console.Write(" Throwing up in catch. ");
                throw new Exception("after caught");
            }
        }
        finally { Console.Write(" Finally!!"); }
        Console.WriteLine(" Done!!!"); // before adding checkboxThrowInCatch, 
        // this would never happen (and was marked grey by ReSharper)
    
    }
    

出力:

  • 1. catch で続行: try で投げます。...キャッチ!ついに!!終わり!!!
  • 2. Return in try: Return in try。ついに!!
  • 3. catch での再実行: try でのスロー。...キャッチ!キャッチで返します。ついに!!
  • 4. スロー イン キャッチ: スロー イン トライ。...キャッチ!キャッチで投げる。ついに!!速報: クラッシュが発生しました。

要約すると: 最後に、次の 2 つの処理を行います。

  1. try または catch で返されたコードの。
  2. または、try で例外があり、かつ catch で例外をスローした場合、
  3. または、try で例外があり、かつその例外をキャッチしなかった場合、

最後に "FINALLY" を要約すると:最後に、試しても特別なことは何もしません。

  1. 戻ってこなかった、
  2. 試行中に例外をキャッチし、その後
  3. キャッチにも戻らなかったし、
  4. スローしなかったか、スローするコードがありました。

最後になりましたが (最後に): コードにキャッチできなかった例外がある場合、コードは FINALY に到達せずに飛行します。

これが明確であることを願っています。(今は私に...)

モシェ

于 2009-07-21T13:25:45.513 に答える
7

違いは、ブロック内のコードがtryブロックによってキャッチされない例外をスローする場合catchです。

通常、catchブロックは特定の種類の例外をキャッチし、それ以外はすべて通過させます。その場合、finallyブロックは引き続き実行されます。

ブロック内のfinallyコードがs.tryreturn

于 2009-07-21T11:38:33.223 に答える
7

最後に、[例外が発生したかどうかにかかわらず] すべての条件で評価する必要があるコードが含まれています。

finally ブロックを実行せずに try ブロックを終了する方法はありません。finally ブロックが存在する場合は、常に実行されます。(このステートメントは、すべての意図と目的に当てはまります。finally ブロックを実行せずに try ブロックを終了する方法があります。コードが try ブロック内から System.exit(0); を実行すると、アプリケーションは finally なしで終了します。一方、try ブロック中にマシンのプラグを抜くと、finally も実行されません。)

主な用途はオブジェクトの破棄です。file 、開いているリソース (db stmts) などのユーザー定義リソースを閉じたい場合に便利です。

編集

また、最終的にスタックオーバーフロー例外の後に実行されません。

于 2009-07-21T11:38:40.603 に答える
3

これは、データベース接続を処理するとき、またはオブジェクトを破棄する必要があるときはいつでも良い考えです。クエリの実行中に問題が発生した場合に備えて、接続を安全に閉じることができます。また、try/catch/finally ブロックの外側のブロックがアクセスできないコードをクリーンアップするのにも役立ちます。

于 2009-07-21T11:39:33.580 に答える
2

例外が原因で関数が終了したかどうかに関係なく、Finally ブロックが実行されます。(この規則にはいくつかの例外があります。詳細については、このスタックオーバーフローの質問を参照してください)。

例えば:

Try
    'Do something
Catch ex As Exception
    if 'Some Condition
       throw ex
    else
       'Handle exception
Finally
    'Do cleanup
End Try

この場合、関数から例外をスローしても、Finally ブロックは実行されます。

これにより、クリーンアップ コードが常に実行されることが保証されるため、これを実践することをお勧めします。もちろん、リソースの取得は初期化のイディオムを使用することは、リソースが確実にクリーンアップされるようにするためのよりクリーンな方法ですが、これが可能かどうかを知るには、私は VB.net に精通していません。

于 2009-07-21T11:44:42.993 に答える
2

最後に、システムの一貫性を保つために必要なすべての作業に慣れる必要があります。これは通常、リソースの解放を意味します

最終的には、スローされた例外に関係なく、常に実行されます。次の場合に、リソースを解放するために使用する必要があります。

  • 接続を確定する
  • ファイル ハンドラーを閉じる
  • 空きメモリ
  • データベース接続を閉じる

完全な例を挙げましょう。ネットワーク経由でメッセージを送信していると想像してください。擬似コード:

// With finally                  |  //Without finally
try{                             |  try{  
  send_message()                 |    send_message() 
} catch(NetworkError){           |  } catch(NetworkError){ 
  deal_with_exception()          |    deal_with_exception()
} finally {                      |  }
  finalizes_connection()         |  finalizes_connection() 
}                                |

両方のコードの唯一の違いは、tryブロックに保持されているものが ではない例外を発生させるNetworkError場合MethodNotFoundです。最初のケースではメソッドfinalizes_connection()が呼び出され、2 番目のケースでは呼び出されません。

接続は、複数のプログラムを通じて自然に行われます。MethodNotFoundでは、他のプログラムに例外が発生した場合はどうなるでしょうか? 最初のケースでは、あなたのプログラムは接続を終了し、他のプログラムは満足します。2 番目のケースでは、他のプログラムが永遠にあなたの応答を待っている可能性があります。他のプログラムが一度に 1 つの接続しか受信できない場合はどうなりますか? 他のプログラムにもバグを犯しただけです。

これは、たとえば、開いたファイルに適用され、他のプログラムは (Windows で) 読み取り用に開くことができません。メモリの場合、解放されることはなく、メモリ リークが発生します。

于 2013-05-23T03:10:16.300 に答える
1

最終的にクリーンアップ コードに使用します。たとえば、db 接続や開いているファイルを閉じる必要があります。例外の有無に関係なく実行する必要があるほぼすべてのクリーンアップ コード

また、例外処理で例外またはその他の例外を再スローする必要がある場合があります。その場合、ブロックの後のコードは実行されません。

于 2009-07-21T11:38:47.687 に答える
1

finally ブロックでクリーンアップを行うのは、確実に実行されるようにするためです。catch ブロックが例外を処理しない場合 (つまり、ログに記録するだけ)、または別の例外が発生した場合でも、finally ブロック内のコードは引き続き実行されます。

于 2009-07-21T11:39:37.530 に答える
1

他の人が言ったことに加えて、意味的には違うと思います。

finally ブロック内のコードは、try-catch 内に含まれるコンテンツに対してファイナライズ タイプのタスクを実行していることを明確に示しています。これで読みやすくなったと思います。

于 2009-07-21T11:41:47.603 に答える
1

私が覚えている限り、.NET コードで try/catch/finally ブロックを使用したことはありません。

一般に、中間層で例外をキャッチする必要はほとんどありません。例外は通常、プレゼンテーション層のトップレベルのハンドラーに伝播されます (ログに記録できるように、層の境界でキャッチされて再スローされる可能性があります)。

したがって、中間層では、リソースがクリーンアップされるように、try/finally (または「using」ステートメント) がより頻繁に表示されます。そして、プレゼンテーション層の最上位ハンドラーの try/catch で。

まれに、例外をキャッチしてクリーンアップを行う必要がある場合は、次のようにリファクタリングすることをお勧めします。

try
{
    ... do something
}
catch
{
   ... handle exception
}
finally
{
   ... cleanup
}

になります:

try
{
    DoSomethingAndCleanup();
}
catch
{
   ... handle exception
}

...
private void DoSomethingAndCleanup()
{
    try
    {
        ... do something
    }
    finally
    {
        ... cleanup
    }
}

私見これはずっときれいです。

于 2009-07-22T20:01:37.943 に答える
0

try catch ブロックの実行のどの部分の後でも、Catch は実行されません。Catch は、例外がスローされ、catch ブロックがその種類の例外を処理できる場合にのみ実行されます。

finally ブロックは、try ブロックが完了したときに実行されるブロックです。完了するとは、正常に終了するか、何らかの方法で終了することを意味します (ループから抜け出す、メソッドから戻る、例外をスローするなど)。

コードを finally ブロックの外に配置して例外がスローされた場合 (たとえば)、例外がキャッチされない場合、または catch ブロックで再スローされる場合、または新しい例外が catch でスローされる場合、コードは実行されない可能性があります。ブロック。finally ブロック内に配置すると、実行されます。

基本的に、クリーンアップは finally ブロックに配置する必要があります。

于 2009-07-21T11:41:09.880 に答える
0

上記の私のコメントへの返信を読んだ後、私はいくつかのことを考えるようになりました.

質問は、問題のコードを知らずに完全に回答することは基本的にできません。

その理由は、すべてのコードを finally ブロックに入れることができるわけではないからです。たとえば、yield ステートメントは、finally (および catch) ブロックでは許可されません。try ブロックには、返されるものと返されないものがある複数の実行分岐がある場合があります。最終的にはすべてのケースで実行されますが、最終的に実行されない例では、クリーンアップコードには当てはまりません。さらに、finally ブロックにジャンプ (goto) することはできませんが、catch ブロックの後のコードにジャンプできることは非常にまれです。finally ブロックから戻ることもできません。

答えが実際のコードに依存する非常にまれなケースではありますが、かなりの数があります。

于 2009-07-22T19:48:05.113 に答える
0

私がよく使うのは (私はそれをアスペクトにカプセル化しましたが、これは私がアスペクトを導出したものです):

public static DoLengthyProcessing(this Control control, Action<Control> action)
{
    Cursor oldCursor = control.Cursor
    try
    {
        control.Cursor = Cursors.WaitCursor;
        action(control);
    }
    catch (Exception ex)
    {
        ErrorHandler.Current.Handler(ex);
    }
    finally
    {
        control.Cursor = oldCursor;
    }
}

または、AOP を使用します (私のように)。

于 2010-05-12T12:52:11.297 に答える