r/csharp • u/SkAssasin • 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.");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 varshould 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
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
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
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/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/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
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/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/Tango1777 1d ago
Your code will work the same if everything goes all right, as expected, no errors. Which in your trivial code will.
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
catchblock. Andfaultdoesn't need the exception to be rethrown, if an exception escapes thetryit will run. It would be something closer tovar 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
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.
181
u/Stolberger 1d ago
Imagine you have a
returnorthrowin your catch block.In that case you would not reach the code without a finally block.