249

ある友人のコードをレビューしていて、彼は try-finally ブロック内で return ステートメントを使用していたと言います。try ブロックの残りの部分は起動しませんが、Finally セクションのコードは起動しますか?

例:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}
4

12 に答える 12

280

簡単な答え: はい。

于 2008-12-05T20:50:47.030 に答える
209

通常、はい。finally セクションは、例外や return ステートメントを含め、何が起こっても実行されることが保証されています。OutOfMemoryExceptionこの規則の例外は、スレッド ( 、 )で発生する非同期例外StackOverflowExceptionです。

そのような状況での非同期例外と信頼できるコードの詳細については、制約付き実行領域についてお読みください。

于 2008-12-05T20:53:23.157 に答える
158

ここに小さなテストがあります:

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("before");
        Console.WriteLine(test());
        Console.WriteLine("after");
    }

    static string test()
    {
        try
        {
            return "return";
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}

結果は次のとおりです。

before
finally
return
after
于 2008-12-05T21:45:00.803 に答える
40

MSDN からの引用

finallyは、前のtryブロックがどのように終了したかに関係なく、コードのステートメント ブロックが実行されることを保証するために使用されます。

于 2008-12-05T21:03:42.057 に答える
20

一般的にはい、finally が実行されます。

次の 3 つのシナリオでは、finally は常に実行されます。

  1. 例外は発生しません
  2. 同期例外(通常のプログラム フローで発生する例外)。
    これには、System.Exception から派生する CLS 準拠の例外と、System.Exception から派生しない非 CLS 準拠の例外が含まれます。非 CLS 準拠の例外は、RuntimeWrappedException によって自動的にラップされます。C# は非 CLS 準拠の例外をスローできませんが、C++ などの言語はスローできます。C# は、CLS に準拠していない例外をスローできる言語で記述されたコードを呼び出している可能性があります。
  3. 非同期 ThreadAbortException
    .NET 2.0 以降、ThreadAbortException は、finally の実行を妨げなくなりました。ThreadAbortException は、finally の前または後にホイストされるようになりました。スレッド アボートが発生する前に try が実際に入力されている限り、finally は常に実行され、スレッド アボートによって中断されることはありません。

次のシナリオでは、finally は実行されません。

非同期 StackOverflowException。
.NET 2.0 以降では、スタック オーバーフローによりプロセスが終了します。finally を CER (Constrained Execution Region) にするためにさらに制約が適用されない限り、finally は実行されません。CER は、一般的なユーザー コードでは使用しないでください。これらは、クリーンアップ コードを常に実行することが重要な場合にのみ使用する必要があります。スタック オーバーフローですべてのプロセスがシャットダウンされ、すべての管理対象オブジェクトがデフォルトでクリーンアップされた後です。したがって、CER が関連する唯一の場所は、プロセスの外部で割り当てられたリソース (たとえば、アンマネージ ハンドル) です。

通常、アンマネージ コードは、ユーザー コードによって使用される前に、何らかのマネージ クラスによってラップされます。マネージ ラッパー クラスは通常、SafeHandle を使用してアンマネージ ハンドルをラップします。SafeHandle は、重要なファイナライザーと、クリーンアップ コードの実行を保証するために CER で実行される Release メソッドを実装します。このため、ユーザー コード全体に散らばる CER を確認する必要はありません。

したがって、最終的に StackOverflowException で実行されないという事実は、プロセスがいずれにせよ終了するため、ユーザー コードには影響しません。SafeHandle または CriticalFinalizerObject の外部で、管理されていないリソースをクリーンアップする必要があるエッジ ケースがある場合は、次のように CER を使用します。ただし、これは悪い習慣であることに注意してください。管理されていない概念は、設計により、管理されたクラスと適切な SafeHandle に抽象化する必要があります。

例えば、

// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{ 
    // This is *NOT* a CER
}
finally
{
    // This is a CER; guaranteed to run, if the try was entered, 
    // even if a StackOverflowException occurs.
}
于 2011-06-23T15:09:38.333 に答える
3

はい。実際、それが finally ステートメントの要点です。何か壊滅的な事態が発生しない限り (メモリ不足、コンピューターの電源が入っていないなど)、finally ステートメントは常に実行する必要があります。

于 2008-12-05T20:54:23.903 に答える
2

System.exit(0); を使用してアプリケーションを終了する場合、最終的には実行されません。のように

try
{
    System.out.println("try");
    System.exit(0);
}
finally
{
   System.out.println("finally");
}

結果は次のようになります:

于 2014-07-03T06:18:36.507 に答える
0

finally ブロックの主な目的は、その中に書かれているものを実行することです。try または catch で何が起こるかに依存するべきではありません。ただし、System.Environment.Exit(1) を使用すると、アプリケーションは次のコード行に移動せずに終了します。

于 2016-04-14T12:41:31.670 に答える
0

finallyシナリオの 99% で、ブロック内のコードが実行されることが保証されますが、次のシナリオを考えてみてください: try->finallyブロック (no catch) を持つスレッドがあり、そのスレッド内で未処理の例外が発生します。この場合、スレッドは終了し、そのfinallyブロックは実行されません (この場合、アプリケーションは引き続き実行できます)。

このシナリオは非常にまれですが、答えが常に「はい」ではなく、ほとんどの場合「はい」であり、まれに「いいえ」であることを示しているだけです。

于 2015-12-16T12:47:31.747 に答える