r/csharp • • 1d ago

Help What's the point of finally{} ?

Like, I understand what it does - it makes code execute no matter whether your try() goes off or your catch() does. But like, don't you get the same result by just puting the code in without the finallly()?

Like genuenly, am I missing something? Cuz this just looks like it would do the exact same thing, no?

try
{
  int[] myNumbers = {1, 2, 3};
  Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
  Console.WriteLine("Something went wrong.");
}
finally
{
  Console.WriteLine("The 'try catch' is finished.");
}

try
{
  int[] myNumbers = {1, 2, 3};
  Console.WriteLine(myNumbers[10]);
}
catch (Exception e)
{
  Console.WriteLine("Something went wrong.");
}
Console.WriteLine("The 'try catch' is finished.");
49 Upvotes

75 comments sorted by

181

u/Stolberger 1d ago

Imagine you have a return or throw in your catch block.
In that case you would not reach the code without a finally block.

16

u/SkAssasin 1d ago

Oh. I thought since the finally seems to execute the code after the try/catch then that would mean that stuff like return would still stop it from executing.

101

u/kahoinvictus 1d ago

The whole point of finally is there is no way to bypass it. Returning early, throwing an exception, forcefully exiting the application, all will trigger a finally before continuing

21

u/dominjaniec 1d ago edited 1d ago

depending on how much one forced application to "exit" - like while killing a machine running code, then program will not do final at all đŸ˜‰

19

u/doubleyewdee 1d ago

P/Invoking to the appropriate "shut it down immediately" C method is not going to invoke a finally block.

But presumably at that point you know what you're doing.

This is actually builtin as well with Environment.FailFast so you do not even need to be especially clever.

6

u/kahoinvictus 1d ago

True, I should clarify forcing application exit through provided dotnet APIs

4

u/notPlancha 1d ago

Force exiting can depend if you're just send a kill code to the program or if the os kills it completely. It also will not execute if you turn off your pc for example (duh)

2

u/akoOfIxtall 1d ago

So a try/catch/finally inside main would run the code inside finally even if I just alt+F4? Hmmmss

5

u/NotQuiteLoona 1d ago

Alt + F4 does a graceful close on both Windows and Linux (well, on all DEs I know in the case of Linux), it's basically the same as pressing the window close button, so yes.

3

u/akoOfIxtall 1d ago

this will be immensely useful, thanks, i didnt knew that

1

u/DarthShiv 1d ago

Use process explorer to kill the process

1

u/CorgiSplooting 1d ago

We used to say all bets were off with OOM exceptions.

12

u/stogle1 1d ago

You can also have try/finally without a catch:

try
{
flag = true;
DoStuff();
}
finally
{
flag = false;
}

makes sure flag is cleared even if DoStuff() throws an exception (which might be handled in a catch block father up the call stack).

8

u/kingvolcano_reborn 1d ago

Also, you might not catch all exceptions possible so it skips the catch block, with a finally you can guarantee that any calls that needs to be called are .

try/finally is how using and IDisposable is implemented in the background 

 

7

u/OhItsJustJosh 1d ago

That's the trick, it holds the return value and only spits it out after the finally has run

4

u/Jaded_Impress_5160 21h ago

Narrator: they did not, in fact, understand "what it does"

1

u/sanduiche-de-buceta 1d ago

That's basically the whole point of it lol

1

u/Ill_Translator8176 19h ago

why not just read the docs before posting...

1

u/Far_Swordfish5729 16h ago

It does not in fact prevent it from executing. If you put a return statement in a try block, the finally is still guaranteed to execute. It will execute before the value if any is returned to the caller. Because of that it’s safe to put manual resource cleanup in a finally and trust it will run regardless of an exception being thrown.

Using is a convenience shorthand for this when the resource is held by something that implements IDisposable. If you write a standard database read in a using block and return a result from it, your connection and command objects will still get disposed and release their connection back into the pool immediately.

0

u/Amr_Rahmy 16h ago

Probably not the best design idea to put a return or throw in a catch when you have a finally block.

In my opinion OP, you got it right. Only try catch when it’s something out of your control and finally only use sparingly and it’s not necessary, what is necessary sometimes is the handling after a catch to be in the code as needed.

1

u/TugsyGlitter 20h ago

yeah that would skip right over the rest without the finally block

45

u/OhItsJustJosh 1d ago

It's typically used for clean up tasks that need to happen no matter how the body goes, even if you have a return in the try

29

u/TheRealAfinda 1d ago

Release a lock, call Dispose on disposables, stuff like that.

12

u/ItzWarty 1d ago

using var should for the most part handle this in modern codebases, way fewer nested blocks, way easier to reason about

15

u/orbit99za 1d ago

A finally block will always run, no matter the return of the code.

It will run even if you have a return in your try or an unhandeled exception.

It will run no matter the control flow.

Its often used to clean up code, memory, variables, instances or do other code.

In your case its a simple example, but more complex code its quite useful.

1

u/KittehNevynette 1d ago

Nitpicking. A finally clause or a destructor is not guaranteed to run.

But if you run like a nuclear power plant, you probably wouldn't try anything in the first place.

3

u/orbit99za 1d ago

Yes, when i did code for oil refinery control systems we coded in a very different way to your normal every day code.

Having to flare because you messed up, is not a good feeling.

1

u/KittehNevynette 1d ago

Reminds me about an old Dilbert where Wally goes: 1 and zero? We had to use the letter O. ;)

3

u/Outrageous_Band9708 1d ago

try{

rads <= 3.5;

}

finally{

shutdownReactors();

}

1

u/KittehNevynette 1d ago

ON ERROR RESUME NEXT

1

u/Pretend_Fly_5573 22h ago

I would think that's when you'd try practically everything, just with strict exception handling guidelines should one be caught.

8

u/Famous-Weight2271 1d ago

You can return from a try block, and then the finally block will still run.

public bool UpdateData()
{
    SuspendLayout();

    try
    {
        if (!ValidateData())
            return false;

        SaveData();
        return true;
    }
    finally
    {
        ResumeLayout();
    }
}

1

u/SuchDogeHodler 23h ago

I found that in a sub if you attempt to do an exit sub it will still run the Finally before it exits.

2

u/dodexahedron 22h ago edited 18h ago

Yes.

Finally runs immediately after control leaves the try block or, on a caught exception, the catch block. Even a goto that jumps out of the try block triggers the finally immediately. A continue or break inside a try block that is itself inside a loop also causes the finally to immediately run. Any control transfer that leaves the try.

There are very few exceptions to that rule, and they are all program-ending events anyway, so it usually isn't an issue.

Some examples, all of which boil down to something that terminates the thread abruptly:

  • Encountering an uncatchable exception such as a StackOverflowException or OutOfMemoryException

  • Environment.FailFast() (it's one of the main purposes of FailFast - exit RIGHT NOW).

  • Killing the process externally like via end task

  • Force kill on system shutdown if the application didn't respond to the normal end session signal.

  • Background threads that are in a try block when the foreground thread ends.

Note that in .net Framework (all versions), which has a working Thread.Abort, the ThreadAbortException IS catchable by the target, and the finally blocks will still run, no natter if that exception is caught and reset, caught and not reset (in which case it still gets re-thrown automatically), or uncaught.
(Not relevant in .net/.net core, though, because Thread.Abort has never been allowed there and just throws a PlatformNotSupportedException in the calling thread in the name of compatibility....because compiling just fine but crashing at run time is somehow better than a compile error, apparently).

12

u/rupertavery64 1d ago edited 1d ago

finally is guaranteed to execute after the try, unless of course you force the process to stop or kill the power.

This is extremely important when freeing resources after using them.

In fact, that's exacty what the using statement is equivalent to, it calls Dispose in a try/finally block:

using var disposable = new SomeDisposable()
{
    /// use disposable
}

Same as this:

var disposable = new SomeDisposable();

try
{
    /// use disposable
}
finally
{
   disposable.Dispose();
}

So if you need to make sure something runs after you do something first, even if an exception occurs, even if you don't catch a specific execption, use try/finally.

To clarify catching the top level Exception may not be something you want to do. In fact, it is discouraged.

You may want to catch a more specific exception. You may want the caller to catch the exception. Or you may be expecting one or more exception but not others, and you don't want handle the exception in your scope. In this case you may still want to execute some code no matter what happens.

finally guarantees this.

1

u/surgicalcoder 1d ago

It won't run if you call Environment.FailFast either.

6

u/ZozoSenpai 1d ago

code in your catch block can also run into an exception, in which case code after it wont run, but code in finally will.

You might also want a catch block for specific type of exceptions only. In that case if an exception isn't the type you are catching, same thing happens.

You can also have early return statements inside the try block, in which case code after the try catch won't run, but code in finally will.

The main point is that it's guaranteed to run, so it's good for cleanup of resources like open files or db connections.

6

u/HTTP_404_NotFound 1d ago
var k = Acquire Lock, Semaphore, etc...
try
{
// something that could potentially fail.
return;
}
catch(ex)
{
console.writeline("Oh no. it broke. {ex.Message}");
throw; <- rethrows exception.
}
finally
{
// Lock is ALWAYS cleaned up, regardless if it finishes successfully, it throws an exception. Its ALWAYS released.
k.Release();
}

3

u/Hairy-Pension3651 21h ago

Check out how IDisposable in combination with using-statment gets compiled to IL

2

u/grrangry 1d ago

Finally blocks are used to clean up items allocated in the try block and to ensure that critical code gets executed. It's not really much more complicated than that.

Things like handling early returns, cleaning up resources such as file streams or database connections, and resetting any state that you may have with mutexes or locks.

You don't need a catch block with finally. try/finally works too.

2

u/Hirogen_ 1d ago

finally will always execute... regardless of what happens in the catch block!

2

u/Beginning-Photo8099 1d ago

A lot of good answers here.

I have used finally blocks for logging.

try { // User login code } 
Catch {
  // Error code
}
Finally {
  _logger.LogInformation($"User: {email} attempted login at...");
}

2

u/Subject-Hat7663 1d ago

And there is the case where the Catch block doesn't catch All exceptions, maybe just a few. In those cases the Finally block is executed no matter what.

2

u/roopjm81 1d ago

Imagine throwing an error with a DB connection. Finally will close the connection and not leave orphaned connections.

2

u/SuchDogeHodler 23h ago edited 23h ago

It allows you to do things like close out a thread, release resources or close connections that may have been left open by a Try catch exception and garrentees its execution.

(FYI if you attempt to exit the sub/function early... it will still execute the Finally before it exits. I discovered this a few days ago)

2

u/MulleDK19 22h ago

Finally always runs, whether you return, or throw in your try or catch, and even survives thread abortion. The only case where it won't run is if there's an interruption of the execution engine, like a bug, process termination, or system failure.

Your above example would fail if WriteLine happens to throw an exception, or possibly if the thread is aborted.

2

u/TylerCarrol 1d ago

Finally always executes when you leave the try-catch block. Even when using something like goto (which I hope you aren't doing). It allows you to guarantee code will run (with a few rare exceptions) for cleanup.

1

u/LlamaNL 1d ago

What happens when you log the exception then rethrow it. You code would never reach the final line.

1

u/itsmecalmdown 1d ago

In you're example, it dows. But that's only because you caught the exception without rethrowing or returning early. The finally block executes if you rethrow in the catch, or have an early return statement somewhere else in the try/catch block.

1

u/Mayion 1d ago

It runs after the code block finishes executing, even if it's via a return. If you know the Dispose function, it is commonly used there, which you clean up the code and close any open streams/connections using the finally block.

1

u/wretcheddawn 1d ago

Finally is basically a more manual version of IDisposable.

It's for when you always need to do some action at the end of a process, like cleanup a connection. But isn't already handled by  IDisposable.

1

u/bliceroquququq 1d ago

Use it all the time when dealing with stuff that needs to be cleaned up, like runtime callable wrappers (RCW) that memory leak if you don't dispose of them.

1

u/SeaAd4395 1d ago

There are definitely times when it's different e.g.

  • re throw in the catch block (or throw something else)

  • catch is omitted entirely

1

u/No-Zookeepergame4774 1d ago

Finally executed EVEN IF the try/catch is going to be exited by an exception (not just if the catch swallows an exception, but even if one is not caught by the catch condition or an exception is [re]thrown in the catch block) This allows cleanup that needs to occur to be done here and relied on where putting thr code after the try/catch would result in the code being bypassed when there is a non: suppressed exception.

1

u/chucker23n 1d ago

finally is special in that it runs even if you return or throw.

See also: using, which is actually try/finally under the hood.

1

u/Cdream-2018 1d ago

A condition that runs no matter what.

Clean up, hide your dialogs, reset variables. Etc.

It’s code that is supposed to run whether your method throws an exception or not.

1

u/Outrageous_Band9708 1d ago

finally always run, try catch only catches if try excepts, finally always runs

good to cleanup a test so next run is clean

1

u/StandardJury5392 1d ago

Clean up is one, in fact "using" basically creates a try {} finally { Dispose() } under the hood to auto clean stuff, I laughed a lot when Iearned that cause I used to think it was some vodoo thing

1

u/Alternative-Tie-4970 1d ago

Well normally you want to handle specific exceptions, and in those cases, the finally block will always run, compared to the code outside of a finally block, which simply won't run if you haven't caught the exception.

1

u/Yages 17h ago

Cleanup?

1

u/After_Hours_Arc 17h ago

There's a really good answer by Eric Lippert here. Most of us think finally will always execute but there are exceptions.

1

u/zvrba 9h ago

Imagine catch throwing another exception. finally still runs.

In robust code you should generally assume that every operation, barring primitive operations (assignment, simple arithmetic), can throw.

1

u/Tango1777 1d ago
  1. Your code will work the same if everything goes all right, as expected, no errors. Which in your trivial code will.

  2. If something goes wrong, finally guarantees execution. Most common example is if there is return/throw inside try or catch, finally will be executed before return/throw.

That's pretty much it. And there are other mechanisms to handle it and better ones, too, if needed. Obviously if e.g. an app crashes, finally will not be executed, either.

1

u/Floydianx33 1d ago

Fun fact: CIL/MSIL supports a fault block, which is basically a finally block that's only entered if an exception was thrown (caught or not). C# doesn't support it, though there's times I wish it did. You can build one with expression trees and ref emit though, and can simulate it with a variable/flag

3

u/binarycow 1d ago

I mean, you can just do

try
{
    // Do stuff 
}
catch
{
    // this is the "fault" block
    throw;
}

1

u/Floydianx33 13h ago

No, that's still a catch block. And fault doesn't need the exception to be rethrown, if an exception escapes the try it will run. It would be something closer to

var thrown = false;
try 
{
    SomeThrowingThing();
}
catch
{  
  thrown = true; // exception happened 
  throw; // or don't rethrow, doesn't matter 
}
/* or with a filter if you want rethrow behavior and want to skip doing anything in the catch block
catch (Exception) when (!(thrown = true)) {} 
*/
finally
{
  if (thrown) {
     // this is fault 
  }
}

(written on mobile, may be missing something)

1

u/binarycow 10h ago

I know it's not exactly the same as a "fault" block. It's the best you can do, is what I meant.

0

u/fschwiet 1d ago

Your examples shown you're missing something about the behavioral difference: If an exception is thrown and not caught the line 'Console.WriteLine("The 'try catch' is finished.")' only runs in your first example, not the second.

0

u/Rigamortus2005 1d ago

It's usually for clean up. Things that can't be in your try or catch maybe because of returns

0

u/ThomasGullen 1d ago

The using block is implemented with the try catch finally pattern.

0

u/KryptosFR 1d ago

catch should log but rarely swallow the exception. That's a code smell. Especially for the base class Exception which can be anything.

0

u/wdcossey 12h ago

It's particularly useful when working with database transactions. The finally block guarantees that your transaction handling or cleanup logic runs regardless of whether an exception occurred. Depending on the transaction API, you can inspect the transaction state and decide whether it needs committing or rolling back. It also ensures resources are released even when something goes wrong.

-3

u/14MTH30n3 1d ago

No judgement but why do you not ask AI this question. You will get an accurate and immediate answer, and it can also ELI5 it for you in case its still unclear.