views:

885

answers:

8

If you run the code below it actually executes the finally after every call to the goto:

    int i = 0;
Found:
    i++;
    try
    {
        throw new Exception();
    }
    catch (Exception)
    {
        goto Found;
    }
    finally
    {
        Console.Write("{0}\t", i);
    }

Why?

+24  A: 

Why do you expect it to not execute?

If you have try/catch/finally or try/finally block, finally block executes no matter what code you may have in the try or catch block most of the time.

Instead of goto, consider 'return'.

//imagine this try/catch/finally block is inside a function with return type of bool. 
try
{
    throw new Exception();
}
catch (Exception)
{
    return false; //Let's say you put a return here, finally block still executes.
}
finally
{
    Console.WriteLine("I am in finally!");
}
SolutionYogi
I guess I thought a goto would override this.
Lucas McCoy
No construct can override this behavior. 'goto'/'return'/any other construct you can imagine.
SolutionYogi
what happens if u have a 'return true;' in the finally block (against the example code above). what get's returned? the false or the true?
Pure.Krome
@Pure.Krome, You can't put a return statement in a finally block.
Jonathon Watney
@Pure.Krome, As Jonathon Watney said, you'll get a "Compiler error CS0157: Control cannot leave the body of a finally clause".
Moayad Mardini
-1. "finally block executes no matter what code you may have in the try or catch block" is clearly wrong: http://stackoverflow.com/questions/833946/in-c-will-the-finally-block-be-executed-in-a-try-catch-finally-if-an-unhandled
Mehrdad Afshari
Mehrdad, that's something I didn't know. Thanks. Answer updated.
SolutionYogi
You guys also might take a look at Eric Lippert's blog post. It's where I got the question from. http://blogs.msdn.com/ericlippert/archive/2009/07/16/iterator-blocks-part-three-why-no-yield-in-finally.aspx
Lucas McCoy
The link to the SO question appears to be dead.
Scott Chamberlain
+2  A: 

That's by design. In the exception handler you can take some exception-specific action. In the finally block you should do resource cleanup - that's why the finally block is always executed no matter what the exception handling code is.

sharptooth
+3  A: 

Seems reasonable. A finally block is always run after either the try or the catch.

Similarly

try
{
  // do something
  return;
}
finally
{
  // do something else
}

will always run the finally block. EDIT - but see Eric's comments above.

Jeremy McGee
A: 

Because a finally statement is expected to execute after leaving the try (or catch when an exception is caught). This includes when you make your goto call.

statenjason
+30  A: 

The following text comes from the C# Language Specification (8.9.3 The goto statement)


A goto statement is executed as follows:

  • If the goto statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. When and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. This process is repeated until the finally blocks of all intervening try statements have been executed.
  • Control is transferred to the target of the goto statement.
Fredrik Mörk
+1 for referencing the spec.
Mehrdad Afshari
+1 for referencing the specification, too.
Moayad Mardini
God! The spec is pretty long ;-)
Lucas McCoy
+1  A: 

As people have mentioned, finally runs no matter the program flow. Of course, the finally block is optional, so if you don't need it, don't use it.

Merus
+9  A: 

The gist of the answers given - that when control leaves the protected region via any means, whether "return", "goto", "break", "continue" or "throw", the "finally" is executed - is correct. However, I note that almost every answer says something like "the finally block always runs". The finally block does NOT always run. There are many situations in which the finally block does not run.

Who wants to try to list them all?

Eric Lippert
According to the spec "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." However, I'd say a StackOverflowException is one, because nothing can deal with it as far as I can see.
Colin Mackay
Personally, I have mentioned the fact that finally is not always run several times on SO (well, let alone things about killing the process and pulling the plug). e.g. http://stackoverflow.com/questions/833946/in-c-will-the-finally-block-be-executed-in-a-try-catch-finally-if-an-unhandled . I think MS docs are not very good warning people about this while they describe `finally`. I think a very small percentage of .NET devs are aware.
Mehrdad Afshari
Colin, indeed, the key point is WHEN CONTROL LEAVES. If control doesn't leave then the finally block does not execute! The try-protected region might contain an infinite loop, for example.
Eric Lippert
@Eric: I totally got this question from your blog post. I also didn't think about an infinite loop in a try/catch block
Lucas McCoy
Environment.FailFast(); and OutOfMemoryException will both avoid running the finallly block.
Neil Whitaker
@neilwhitaker1: When one of those things happens, does control really leave the Finally block, or does control just plain die? How about saying "control won't go anywhere outside the finally block without executing it first, absent the OS killing or taking over the thread and tossing the concept of "control flow" out the window?
supercat
+1  A: 

That is the point of the finally block. It always executes (pretty much).

fastcodejava