tags:

views:

527

answers:

12

Possible Duplicate:
Will code in a Finally statement fire if I return a value in a Try block?

Consider the following code C# code. Does the "finally" block execute?

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);
   }
}

Ha, after I got done writing this, I realized I could have done tested this myself in Visual Studio. However, please feel free to answer!

A: 

Simple answer Yes. But there are some "exceptions" to the rule.

Jerod Houghtelling
did you see the `return` statement?
Gary Willoughby
@Gary: the return statement is no excuse.
EFraim
It will still enter the Finally statement regardless of the return statement.
Jamie Keeling
What are the exceptions I'm curious to hear them.
JonH
Thanks! I didn't know that, i was under the impression the `return` statement bypassed the `finally` block. Good to know it doesn't. :)
Gary Willoughby
@JonH See the duplicate thread... "An exception to this rule is an asynchronous exception happening on the thread (ThreadAbortException, OutOfMemoryException, StackOverflowException)."
Jerod Houghtelling
+2  A: 

yes it does :-) http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx

Ian Jacobs
No, it doesn't. http://thedailywtf.com/Articles/My-Tales.aspx
Ivan Zlatanov
+1  A: 

Yes, finally always executes, now whether or not the code in the finally block will cause an exception is a different story.

Quintin Robinson
+3  A: 

From MSDN try-finally (C# Reference)

The finally block is useful for cleaning up any resources allocated in the try block as well as running any code that must execute even if there is an exception. Control is always passed to the finally block regardless of how the try block exits.

Leniel Macaferi
+1  A: 

Yes, under normal circumstances (as many others have pointed out).

The finally block is useful for cleaning up any resources allocated in the try block as well as running any code that must execute even if there is an exception. Control is always passed to the finally block regardless of how the try block exits.

Whereas catch is used to handle exceptions that occur in a statement block, finally is used to guarantee a statement block of code executes regardless of how the preceding try block is exited.

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

Zano
+10  A: 

From msdn C# specification of the try statement.

The statements of a finally block are always executed when control leaves a try statement. This is true whether the control transfer occurs as a result of normal execution, as a result of executing a break, continue, goto, or return statement, or as a result of propagating an exception out of the try statement.of the try statement.

Source link:

http://msdn.microsoft.com/en-us/library/aa664733(v=VS.71).aspx

There are the cases where the finally block will not execute.

  1. Environment.FailFast
  2. the Uncatchable execeptions
  3. Power Failure
msarchet
i did not know that! :)
Gary Willoughby
@Gary Willoughby, I knew it did but I didn't want to be wrong so I just googled up the spec.
msarchet
+15  A: 

No it does not. It will always execute provided the application is still running (except during a FastFail exception, MSDN link, like others noted). It will execute when it exits the try/catch portion of the block.

It will NOT execute if the application crashes: gets killed through a kill process command etc. This is highly important, because if you write code that absolutely expects it to run, like manually doing a roll back, and if not other wise it will automatically commit, you can run into a scenario the application aborts before that happens. Honestly, this is an outside scenario, but it is important to take note of in those situations.

Kevin
This also includes some Exceptions (the three .net Exceptions that can't be caught), Application.FailFast or a Power Outage (http://thedailywtf.com/Articles/My-Tales.aspx)
Michael Stum
And it won't execute if the code doesn't compile and run, as this probably won't, because of the return statement.
DOK
@DOK What's wrong with the Return Statement?
Michael Stum
"... provided the application is still running." Great catch.
Zano
@ Michael Sturn As you might surmise from several comments, including the very first one below the question, the original code as posted would not have compiled. Apparently it just contained a typo, which has been fixed.
DOK
[It's good to keep this in mind - finally is *not* absolutely guaranteed.](http://thedailywtf.com/Articles/My-Tales.aspx)
Stephen Cleary
This is what Constrained Execution Regions (CER's) are for.
Greg D
There is one more scenario worth mentioning: if the code inside the try block never returns. Infinite loop for instance.
Remus Rusanu
ooh good call @Remus, I didn't think about that one.
Kevin
@Remus: No, `finally` will get called as soon as the infinite loop completes...
Steven Sudit
Lol, yeah, we're all still waiting for the first ever infinite loop to complete ;)
Remus Rusanu
@Remus: While it does run at O(infinity), CPU speed makes all the difference!
Steven Sudit
@Steven well then thank goodness, I wrote my infinite loop to use all the cores in my system!
Kevin
@Kevin: No, that's a mistake. The infinite loop is a purely single-threaded algorithm, so it does not benefit at all from parallelism. In fact, it's probably best if you only run it on a single core.
Steven Sudit
I'm sure there is some academik somewhere working on the problem of partitioning the infinite loop... Turing award is waiting!
Remus Rusanu
@Remus: The Google Indexer Robot is a fine example of a partitioned infinite loop. It not only spans cores but machines.
Steven Sudit
A: 

The right answer is Yes.

Try to debug your program and put a break point and watch as control still hits the finally block.

JonH
+1  A: 

No it doesn't.

There's only a single way around it though and that is Environment.FailFast(). See http://msdn.microsoft.com/de-de/library/ms131100.aspx. In every other case it is guaranteed that finalizers get executed ;-)

The FailFast method writes the message string to the Windows Application event log, creates a dump of your application, and then terminates the current process. The message string is also included in error reporting to Microsoft.

Use the FailFast method instead of the Exit method to terminate your application if the state of your application is damaged beyond repair, and executing your application's try/finally blocks and finalizers will corrupt program resources.

Johannes Rudolph
Anything that terminates the process outright instead of letting it close itself down gently is going to prevent `finally` from running.
Steven Sudit
+7  A: 

It is not totally true that finally will always be executed. See this answer from Haacked:

Two possibilities:

  • StackOverflowException
  • ExecutingEngineException

The finally block will not be executed when there's a StackOverflowException since there's no room on the stack to even execute any more code. It will also not be called when there's an ExecutingEngineException, which is very rare.

In fact, for any sort of asynchronous exception (like StackOverflowException, OutOfMemoryException, ThreadAbortException) the execution of a finally block is not guaranteed.

However, these exceptions are exceptions you usually cannot recover from, and in most cases your process will exit anyway.

In fact, there is also at least one other case where finally is not executed as described by Brian Rasmussen in a now deleted question:

The other case I am aware of is if a finalizer throws an exception. In that case the process is terminated immediately as well, and thus the guarantee doesn't apply.

The code below illustrates the problem

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();
   }
}

A reliable try/catch/finally will have to use Constrained Execution Regions (CER). An example is provided by 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;
    }
}

An excellent source of information is the following article:

Reliability Best Practices

0xA3
Could you please back up what you said about `ThreadAbortException` not triggering `finally`?
Steven Sudit
Agreed, I'm pretty sure ThreadAbortException does attempt to execute the finally block. It favors the finally block over actually aborting the thread, so the latter is less guaranteed than the former.
David
@Steven Sudit, @David: Sorry, I probably wasn't right about this. I somehow had this in the back of my head but MSDN clearly states that `finally` will be executed.
0xA3
ThreadAbortException is a very unusual case, in that it can be caught, but gets automatically rethrown, unless the code has the rights required to call a method that suppresses the rethrow. Since there's this whole mechanism for dealing with it getting caught, it follows that it can't bypass `finally`.
Steven Sudit
You're right, of course, about `StackOverflowException` not triggering `finally`. However, under some circumstances, it doesn't kill the entire process, either. "An application that hosts the CLR can change the default behavior and specify that the CLR unload the application domain where the exception occurs, but lets the process continue." http://msdn.microsoft.com/en-us/library/w6sxk224(VS.90).aspx
Steven Sudit
@Steven Sudit: However, in case of an AppDomain unload execution of `finally` blocks is not guaranteed either. I think it's best explained in the following article, which also mentions the `ThreadAbortException`: [Reliability Best Practices](http://msdn.microsoft.com/en-us/library/ms228970.aspx)
0xA3
Very useful link, thanks.
Steven Sudit
+1  A: 

The finally block will run, right between these lines:

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

Stackoverflow won't

class Program
    {
        static void Main(string[] args)
        {

            try
            {

                Recurse();
            }
            catch
            { }
            finally
            {
                Console.WriteLine("finally");
                Console.ReadLine();
            }
        }

        static void Recurse()
        {
            Recurse();
        }
    }
Conrad Frix