web-dev-qa-db-ja.com

C#「最終的に」ブロックは常に実行されますか?

可能性のある複製:
Tryブロックに値を返すと、Finallyステートメントのコードが起動しますか?

次のコードC#コードを検討してください。 「最終」ブロックは実行されますか?

public void DoesThisExecute() {
   string ext = "xlsx";
   string message = string.Empty;
   try {
      switch (ext) {
         case "xls": message = "Great choice!"; break;
         case "csv": message = "Better choice!"; break;
         case "exe": message = "Do not try to break me!"; break;
         default:
            message = "You will not win!";
            return;
      }
   }
   catch (Exception) {
      // Handle an exception.
   }
   finally {
      MessageBox.Show(message);
   }
}

ハ、これを書いた後、私はVisual Studioでこれを自分でテストできたことに気付きました。ただし、お気軽にご回答ください!

65
Ryan Rodemoyer
5
Ian Jacobs

いいえ、違います。アプリケーションがまだ実行されている場合は常に実行されます( FastFail 例外、 MSDNリンク 、その他の注記の場合を除く)。ブロックのtry/catch部分を終了するときに実行されます。

アプリケーションがクラッシュした場合は実行されません。killprocessコマンドなどで強制終了されます。これは非常に重要です。コミットすると、それが発生する前にアプリケーションが異常終了するシナリオを実行できます。正直なところ、これは外部のシナリオですが、そのような状況では注意することが重要です。

80
kemiller2002

tryステートメントのMSDN C#仕様から:

finallyブロックのステートメントは、制御がtryステートメントを離れると常に実行されます。これは、breakcontinuegoto、またはreturnステートメントを実行した結果として、通常の実行の結果としてコントロール転送が発生する場合でも当てはまります。 、またはtryステートメントから例外を伝播した結果として。

ソース

Finallyブロックが実行されない場合があります。

  1. Environment.FailFast
  2. キャッチできない例外タイプ
  3. 停電
50
msarchet

finallyが常に実行されるとは限りません。 この回答 from Haacked を参照してください:

2つの可能性:

  • StackOverflowException
  • ExecutingEngineException

StackOverflowExceptionが発生すると、finallyブロックは実行されません。スタックにコードを実行する余地がないためです。また、非常にまれなExecutingEngineExceptionがある場合にも呼び出されません。

実際、あらゆる種類の非同期例外(StackOverflowExceptionOutOfMemoryExceptionThreadAbortExceptionなど)の場合、finallyブロックの実行は保証されません。

ただし、これらの例外は通常は回復できない例外であり、ほとんどの場合、プロセスは終了します。

実際、 Brian Rasmussen by now deleted question で説明されているように、finallyが実行されない他のケースも少なくとも1つあります。

私が知っている他のケースは、ファイナライザが例外をスローする場合です。その場合、プロセスもすぐに終了するため、保証は適用されません。

以下のコードは問題を示しています

static void Main(string[] args) {
   try {
      DisposableType d = new DisposableType();
      d.Dispose();
      d = null;
      GC.Collect();
      GC.WaitForPendingFinalizers();
   } catch {
      Console.WriteLine("catch");
   } finally {
      Console.WriteLine("finally");
   }
}

public class DisposableType : IDisposable {
   public void Dispose() {
   }

   ~DisposableType() {
      throw new NotImplementedException();
   }
}

信頼できるtry/catch/finallyは Constrained Execution Regions(CER) を使用する必要があります。 はMSDNによって提供されます:

[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
    public IntPtr m_outputHandle;
}

sealed class MySafeHandle : SafeHandle
{
    // Called by P/Invoke when returning SafeHandles
    public MySafeHandle()
        : base(IntPtr.Zero, true)
    {
    }

    public MySafeHandle AllocateHandle()
    {
        // Allocate SafeHandle first to avoid failure later.
        MySafeHandle sh = new MySafeHandle();

        RuntimeHelpers.PrepareConstrainedRegions();
        try { }
        finally
        {
            MyStruct myStruct = new MyStruct();
            NativeAllocateHandle(ref myStruct);
            sh.SetHandle(myStruct.m_outputHandle);
        }

        return sh;
    }
}

優れた情報源は次の記事です。

信頼性のベストプラクティス

33
Dirk Vollmar

MSDNから try-finally(C#リファレンス)

Finallyブロックは、tryブロックに割り当てられたリソースをクリーンアップしたり、例外が発生した場合でも実行する必要があるコードを実行したりするのに役立ちます。 tryブロックがどのように終了するかに関係なく、制御は常にfinallyブロックに渡されます

4

はい、通常の状況では(他の多くの人が指摘しているように)。

Finallyブロックは、tryブロックに割り当てられたリソースをクリーンアップしたり、例外が発生した場合でも実行する必要があるコードを実行したりするのに役立ちます。 tryブロックの終了方法に関係なく、制御は常にfinallyブロックに渡されます。

Catchはステートメントブロックで発生する例外の処理に使用されますが、finallyは前のtryブロックの終了方法に関係なくコードのステートメントブロックの実行を保証するために使用されます。

http://msdn.Microsoft.com/en-us/library/zwc8s4fz.aspx

2
Zano

これらの行の間で、finallyブロックが実行されます。

message = "You will not win!";
return;
2
David Crowell

はい、finallyは常に実行されますが、finallyブロックのコードが例外を引き起こすかどうかは別の話です。

1

正解は「はい」です。

プログラムをデバッグし、ブレークポイントを設定して、コントロールが最終ブロックにヒットするのを確認してください。

1
JonH

いいえ、そうではありません。

しかし、それを回避する方法は1つしかなく、それはEnvironment.FailFast()です。 http://msdn.Microsoft.com/de-de/library/ms131100.aspx を参照してください。他のすべてのケースでは、ファイナライザが実行されることが保証されています;-)

FailFastメソッドは、メッセージ文字列をWindowsアプリケーションイベントログに書き込み、アプリケーションのダンプを作成してから、現在のプロセスを終了します。メッセージ文字列は、Microsoftへのエラー報告にも含まれています。

アプリケーションの状態が修復できないほど破損している場合、Exitメソッドの代わりにFailFastメソッドを使用してアプリケーションを終了します。アプリケーションのtry/finallyブロックとファイナライザを実行すると、プログラムリソースが破損します。

1

簡単な答えはい。しかし、ルールにはいくつかの「例外」があります。

0