nlawalker
nlawalker

Reputation: 6514

.NET Core: Finally block not called on unhandled exception on Linux

I have created the following C# program:

namespace dispose_test
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var disp = new MyDisposable())
            {
                throw new Exception("Boom");
            }
        }
    }

    public class MyDisposable : IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine("Disposed");
        }
    }
}

When I run this using dotnet run, I see the following behavior:

The delay on Windows is annoying, but the fact that Dispose() isn't called at all on Linux is troubling. Is this expected behavior?

EDITS Clarifications/additions from the conversation below:

Version details:

Upvotes: 19

Views: 1945

Answers (2)

Tom Deseyn
Tom Deseyn

Reputation: 1885

If you surround this with a try-catch, the finally block will run when the exception is caught (handled) by the outer catch.

    static void Main(string[] args)
    {
        try
        {
            using (var disp = new MyDisposable())
            {
                throw new Exception("Boom");
            }
        }
        catch (Exception e)
        {
            throw;
        }
    }

Upvotes: 2

nlawalker
nlawalker

Reputation: 6514

Official response is that this is an expected behavior.

Interestingly enough, the C# doc page on try-finally explicitly calls this out right at the top (emphasis mine)

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

One thing I found in my experimentation is that it doesn't appear to be enough to catch the exception, you have to handle it as well. If execution leaves the catch block via a throw, the finally will not run.

Upvotes: 15

Related Questions