0

I have this test code. Why is the dispose method not called when an exception is raised inside using statement? According to the documentation it should be called.

using System;
using System.IO;
using System.Text;

namespace UsingTest {
    class Program {
    public class MyClass : IDisposable
    {
        private bool disposed = false;

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        public void Dispose(bool disposing) {
            if (!disposed) {
                if (disposing) {
                    using (var f = new FileStream("log.txt", FileMode.Create)) {
                        var msg = "MyClass disposed";
                        f.Write(Encoding.UTF8.GetBytes(msg), 0, Encoding.UTF8.GetByteCount(msg));
                    }
                }
                disposed = true;
            }
        }

        ~MyClass() {
            Dispose(false);
        }
    }

    static void Main(string[] args) {
        using (var c = new MyClass()) {
            Console.WriteLine("some work");
            throw new Exception("Exception");
            Console.WriteLine("Hello World!");
        }
    }
}
}

Thanks.

Peter Bons
  • 26,826
  • 4
  • 50
  • 74
scribe
  • 163
  • 1
  • 10
  • 5
    How do you verify that the code isn't called? Could it be that it has a different default directory than what you expect so that the log file isn't where you expected it to be? To be clear, I tested your code, **the dispose method *is* called**, the file is produced. Since the code in the question doesn't reproduce the problem you're describing I'm voting to close. – Lasse V. Karlsen Mar 05 '18 at 09:24
  • 1
    I tried the code as well, and like Lasse I saw the file being created. – Jon Skeet Mar 05 '18 at 09:27
  • @LasseVågsætherKarlsen if you will run it from Visual Studio with debugger - it will not be called. – Evk Mar 05 '18 at 09:27
  • @Evk If you mean, "the dispose method has yet to be called when the debugger stops on the exception", then yes, that is to be expected. Is that what you meant? – Lasse V. Karlsen Mar 05 '18 at 09:28
  • very strange things happening) – scribe Mar 05 '18 at 09:28
  • @LasseVågsætherKarlsen not exactly. It will break on exception but then if you will continue (with F5 for example), and application will exit - it will not be called (because VS will kill the process without giving a chance for finally blocks to execute). That's what OP does I think. – Evk Mar 05 '18 at 09:28
  • 2
    Yes, that may be right, I see this behavior here too, seems like a bug with the debugger if you ask me. – Lasse V. Karlsen Mar 05 '18 at 09:30
  • it's not calling when launching from studio and even project opened. but when i closed project solution and run exe file, its creating normal. – scribe Mar 05 '18 at 09:30
  • 2
    It seems Visual Studio figures out that the exception is unhandled, and thus simply aborts if you hit F5 to continue. This, to me, sounds like a bug, since "unhandled exception" is definitely not the same as "no more code to execute". A valid debugging scenario is actually to verify that the application shuts down gracefully on an exception, and thus cleans up temporary files or whatnot. Again, this definitely sounds like a bug. There could be a good reason for why it is like it is though, but still. – Lasse V. Karlsen Mar 05 '18 at 09:33
  • 2
    Please clear up in the question that this is actually a question about the debugger since I think we've verified that the application by itself actually does what is expected, in other words, the code by itself is not the issue here, the way the debugger handles an unhandled exception is. – Lasse V. Karlsen Mar 05 '18 at 09:37
  • @LasseVågsætherKarlsen you can read Eric Lippers opinion on a similar matter: https://stackoverflow.com/a/4196863/5311735. It's not exactly the same situation (no debugger), but similar in a sense that on unhandled exception finally blocks might or might not be run and that is by design. – Evk Mar 05 '18 at 10:14
  • Then it seems this is by design. – Lasse V. Karlsen Mar 05 '18 at 10:25

1 Answers1

5
static void Main(string[] args) {

        using (var c = new MyClass()) {
            Console.WriteLine("some work");
            throw new Exception("Exception");
            Console.WriteLine("Hello World!");
        }

    }

This is creating a new instance of MyClass
While it's instantiated, it writes to the console. Then throws an exception. On exception, the debugger steps in, and tries to help you out debugging the code. The debugger in Visual Studio will keep running your code long enough to do that - debug it.

if you will run it from Visual Studio with debugger - it will not be called

The method (Dispose) is being called after the debugger stops running / listening to your code.

Your breakpoints in Dispose won't be hit, since the debugger is no longer there. The code isn't being run, since the runtime has exited (by order of Visual Studio determining you're now finished)

If you run it without debugging (ctrl+f5) you will see the file created too.

Try putting a System.Diagnostics.Debugger.Launch(); inside your Dispose method, like this:

public void Dispose(bool disposing) {
    System.Diagnostics.Debugger.Launch();
    //etc
}

This will attach the debugger at that point in time.

Alex
  • 37,502
  • 51
  • 204
  • 332
  • 1
    This is explaining the behavior, I still don't know if this is by design. While it is correct that an unhandled exception will take the application down, there is definitely opportunity for the program and user-code to execute along that path, debugging this execution flow is definitely something worth doing. I would explore if this is by design or by happenstance. – Lasse V. Karlsen Mar 05 '18 at 09:39