Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using statement doesn't work correctly [closed]

My class named S looks like that:

public class S : IDisposable
{
    public void Dispose()
    {
        // some code
    }

    public void f()
    {
        throw new Exception("exception");
    }
}

When I use using statement, f() method doesn't call s.Dispose() method. I thought it should call Dispose method even if the exception occurs. That's what I read in MSDN: "The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object". Am I missing something?

using (S s = new S())
{
    s.f();
}

Calling s.f() ends my program without disposing of my object s. I think I don't have to use try/catch, because using statement should do it for me.

like image 996
alcohol is evil Avatar asked Sep 24 '14 14:09

alcohol is evil


2 Answers

Am I missing something?

A using statement is converted into a try ... finally statement.

According to the try ... finally C# reference,

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.

So yes, you are missing something: that a finally block (and thus a call to Dispose in a using statement) is not guaranteed to fire in all circumstances, including in your circumstance, that of an unhandled exception.

The page goes on to advise:

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.

I'd be happier if I could find references in the C# specification. Unfortunately my reading of §8.9.5 is that even an unhandled exception should cause all finally statements on the way up the stack to execute.

like image 99
Rawling Avatar answered Sep 20 '22 18:09

Rawling


The problem might be that you are running the code in the debugger. That means that whatever code comes after an unhandled exception wont be executed becuase the debugger will halt at that point.

If you run a test scenario out of the debugger then the Dispose() method will be called when the runtime cleans up the mess. Put some code "marker" in the Dispose() method that will give you a visible sign that Dipose is called: for example create a file in some accessible folder namesd DisposedHasRun.yeah (note that outputting to the Console or a MessageBox is not an option because the application is quitting due to an unhandled exception). When you run the test case outside the debugger you'll see that the file has been created.

That said, there are ocassions where Dispose wont be called (nor finally blocks). For example an StackOverflow exception due to an infinite recursion will not call Dispose() as the runtime will make the application bail out asap. (ThreadAbortException I think will behave the same)

like image 25
InBetween Avatar answered Sep 23 '22 18:09

InBetween