111

Are there situations where it is appropriate to use a try-finally block without a catch block?

DavidRR
  • 18,291
  • 25
  • 109
  • 191
mkus
  • 3,357
  • 6
  • 37
  • 45
  • 2
    On MSDN, see [try-finally (C# Reference)](https://msdn.microsoft.com/en-us/library/zwc8s4fz%28v=vs.140%29.aspx). Note that the article refers to the combined use of `try` and `finally` as the "**try-finally** *statement*." – DavidRR Mar 24 '16 at 13:00

10 Answers10

169

You would use it to ensure some actions occur after the try content or on an exception, but when you don't wish to consume that exception.

Just to be clear, this doesn't hide exceptions. The finally block is run before the exception is propagated up the call stack.

You would also inadvertently use it when you use the using keyword, because this compiles into a try-finally (not an exact conversion, but for argument's sake it is close enough).

try
{
    TrySomeCodeThatMightException();
}
finally
{
    CleanupEvenOnFailure();
}

Code running in finally is not guaranteed to run, however the case where it isn't guaranteed is fairly edge - I can't even remember it. All I remember is, if you are in that case, chances are very good that not running the finally isn't your biggest problem :-) so basically don't sweat it.

Update from Tobias: finally will not run if the process is killed.

Update from Paddy: Conditions when finally does not execute in a .net try..finally block

The most prevalent example you may see is disposing of a database connection or external resource even if the code fails:

using (var conn = new SqlConnection("")) // Ignore the fact we likely use ORM ;-)
{
    // Do stuff.
}

Compiles into something like:

SqlConnection conn;

try
{
    conn = new SqlConnection("");
    // Do stuff.
}
finally
{
    if (conn != null)
        conn.Dispose();
}
Community
  • 1
  • 1
Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
  • Is there a good reason to do this? Is hiding exceptions not very bad practice!? – AnthonyBlake Feb 15 '12 at 10:21
  • 19
    @AnthonyBlake The exception isn't hidden. If an exception occurred, it would run the finally and then propagate the exception back up the call stack. – Adam Houldsworth Feb 15 '12 at 10:22
  • 2
    As for the edge case, the finally won't run if the process is killed (with "terminate process" in the task manager or because of a power outage, for example). – Nuffin Feb 15 '12 at 10:42
  • @Tobias thanks for the extra info - I'll update the answer. I put it in there for technical correctness, as it's a misconception (although largely harmless) that finally is guaranteed. – Adam Houldsworth Feb 15 '12 at 10:43
  • 1
    More information here about when a finally statement will not fire - not just when process is killed: http://stackoverflow.com/questions/111597/conditions-when-finally-does-not-execute-in-a-net-try-finally-block – Paddy Feb 15 '12 at 11:20
  • 1
    Another obvious case where not *all* of the finally will run is if an error happens in the midst of the finally block. – Ben Hocking Feb 15 '12 at 12:28
  • @BenHocking True, but in that case the finally is still actually called - in the other edge cases I was referring to, the finally isn't even entered. – Adam Houldsworth Feb 15 '12 at 12:35
  • 4
    Finally will not be called in three scenarios I can think of: Killing the process, stack overflow, and out of memory. All of these basically halt execution of the program at the exact point they are encountered and signal the OS to terminate the process. – KeithS Feb 15 '12 at 15:33
8

Good Explaination using code:

void MyMethod1()
{
    try
    {
        MyMethod2();
        MyMethod3();
    }
    catch(Exception e)
    {
        //do something with the exception
    }
}


void MyMethod2()
{
    try
    {
        //perform actions that need cleaning up
    }
    finally
    {
        //clean up
    }
}


void MyMethod3()
{
    //do something
}

If either MyMethod2 or MyMethod3 throws an exception, it will be caught by MyMethod1. However, the code in MyMethod2 needs to run clean up code, e.g. closing a database connection, before the exception is passed to MyMethod1.

http://forums.asp.net/t/1092267.aspx?Try+without+Catch+but+with+finally+doesn+t+throw+error+Why+no+syntax+error+

donstack
  • 2,557
  • 3
  • 29
  • 44
  • 2
    Ann example of this 'clean-up' could be saveLogFile(), which I often want to put at the very end of a program no matter what. – Vincent Oct 29 '17 at 19:51
5

using is equivalent to try-finally. You will only use try-finally when you want to do some clean up inside finally and don't care about the exception.

The best approach will be

try
{
   using(resource)
   {
       //Do something here
   }   
}catch(Exception)
{
     //Handle Error
}

Doing so even clean up called by using fails, your code will not fail.

There are some condition when finally will not get executed.

  • If there is any StackOverflowException or ExecutingEngineException.
  • Process is killed from external source.
TylerH
  • 20,799
  • 66
  • 75
  • 101
Amar Palsapure
  • 9,590
  • 1
  • 27
  • 46
4

If you have, for example an unmanaged resource you create and use in the try block, you can use the finally block to ensure you release that resource. The finally block will always be executed despite what happens (e.g. exceptions) in the try block.

E.g. the lock(x) statement is really:

System.Threading.Monitor.Enter(x); 
try { ... } 
finally 
{ 
    System.Threading.Monitor.Exit(x); 
} 

The finally block will always get called to ensure the exclusive lock is released.

Jeb
  • 3,689
  • 5
  • 28
  • 45
1

Here is a situation where you might want to use try finally: when you would normally use a using statement, but can't because you are calling a method by reflection.

This won't work

using (objMsg  =  Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("omApp.MessagingBO")))
{

}

instead use

           object objMsg = null;
            try
            {
                objMsg
                   = Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("myAssembly.objBO"));

                strResponse = (string)objMsg.GetType().InvokeMember("MyMethod", BindingFlags.Public
                        | BindingFlags.Instance | BindingFlags.InvokeMethod, null, objMsg,
                        new object[] { vxmlRequest.OuterXml });
            }               
            finally
            {
                if (objMsg!=null)
                    ((IDisposable)objMsg).Dispose();
            }
jazza1000
  • 4,099
  • 3
  • 44
  • 65
1

You need a finally block, when no matter which (if any) exceptions are caught or even if none are caught you still want to execute some code before the block exits. For instance, you might want to close an open file.

See Also try-finally

IanNorton
  • 7,145
  • 2
  • 25
  • 28
1

try/finally: when you do not want to handle any exceptions but want to ensure some action(s) occur whether or not an exception is thrown by called code.

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
1

I don't know anything about C#, but it seems that anything you could do with a try-finally, you could more elegantly do with a using statement. C++ doesn't even have a finally as a result of its RAII.

Community
  • 1
  • 1
Neil G
  • 32,138
  • 39
  • 156
  • 257
  • Not necessarily. What if you want to run some custom code that isn't handled by simple disposing. For instance, if you increase a counter in the `try`, then decrease it in a `finally`, you can't do that in a `using` statement. – Mark A. Donohoe Oct 30 '20 at 04:51
  • @MarkA.Donohoe Can you not create a object that holds a reference to the counter, which it decrements when it is disposed? – Neil G Oct 30 '20 at 06:26
  • Yes, but why create an entire object just to implement a disposable interface to use with the using statement? That's fitting the problem to the solution. A `Try-[Catch]-Finally` handles all of that without having to create such an object. – Mark A. Donohoe Oct 30 '20 at 06:37
  • @MarkA.Donohoe The object solution is superior because it implements a bracketing pattern in one place. You cannot forget, misplace, or accidentally delete the decrementation code. – Neil G Oct 30 '20 at 06:44
  • I'm sorry, but I disagree. You're focusing on explicit decrementing behavior, but who said they had to be perfectly matched? What if there is other increment/decrement logic that also depends on other members in the function? Plus, you're now not only introducing a new object just for one use, but you're doing so on the heap instead of a simple int on the stack. There is definitely a time and a place to use `using` but you can't make the blanket statement like you have. Again, that's defining the problem by the solution, which to me is backwards. – Mark A. Donohoe Oct 30 '20 at 06:56
  • @MarkA.Donohoe They have to be "perfectly matched" because this question is about try-finally, which implements a "perfectly matched" bracketing pattern. Whatever you can do with try-finally, you can do more elegantly with an object and a using-statement. The heap/stack question is probably irrelevant with a good optimizer, and for most cases, writing clear code is superior to writing assembly-like code. – Neil G Oct 30 '20 at 07:00
  • Again, that's not a true statement. `finally` simply means you want something to happen regardless if there's an exception or not. No one said those two things have to be related. For instance, say you want to log something or something else. There's no matched/paired log statement, only one or more exceptions somewhere in the try block. But it's ok, we'll just have to agree to disagree here. That's the great thing about programming. Lots of different patterns and we can all choose what we want. – Mark A. Donohoe Oct 30 '20 at 07:03
  • "No one said those two things have to be related." — Whatever is in the finally is related to the reason that you opened the try. For example the creation of a database connection or use of a resource. Feel free to look through the examples here or elsewhere. try-finally always implements a bracketing pattern. In your idea of logging in finally, there must be some reason why you choose to put the try in a particular place. That reason is the matching pair. – Neil G Oct 30 '20 at 07:09
  • Yes, it's related to what happens inside the `try`, but with a `using` statement, that depends on creating, then disposing an object. `using` is a convenience method for a try-catch *for the specific use-case of `IDisposable`* but try-catch doesn't *have* to use `IDisposable`. That's what I mean by it being backwards. For instance, you could have a `try` block with ten statements that each can raise an exception. However, none of them themselves have a related object in the `finally` block, like a 'log' statement, thus there's nothing to dispose and creating such an object to me is overkill. – Mark A. Donohoe Oct 30 '20 at 07:27
  • @MarkA.Donohoe I think you've misunderstood. You don't create an object for everything in the try block. You create one object for the entire finally block at the place at which you opened the try block. – Neil G Oct 30 '20 at 08:20
  • I understood what you said. It's you misunderstanding me. The TLDR is I simply disagree with your statements that `IDisposable` with a `using` is always 'more elegant' or 'superior' to a `try-catch-finally`. Yes, `using` is more elegant when the thing you need to clean up in the finally block already implements `IDisposable`, but introducing `IDisposable` with `using` just to avoid a `try-finally` adds unnecessary noise/complexity. Time and place for everything. Anyway, I think we've beat this to death so feel free to reply if you want, but not much else I can add here. We just disagree. – Mark A. Donohoe Oct 30 '20 at 08:32
0

1.we can use the try block without catch but we should use the catch/finally, any one of them. 2.We can't use only try block.

0

Have a look at the following link: https://softwareengineering.stackexchange.com/questions/131397/why-use-try-finally-without-a-catch-clause

It depends on the architecture of your application and the operation you are performing in the block.

Community
  • 1
  • 1
Harsh
  • 3,683
  • 2
  • 25
  • 41