6

I have

void foo1()
{
   using(...){...}
}

void foo2()
{
   using(...){...}
}

void foo3()
{
   using(...){...}
}

and I have

void foo()
{
    ...
    backgroundWorker.DoWork += (s, ev) =>
                                           {
                                               try
                                               {
                                                   foo1();
                                                   foo2();
                                                   foo3();
                                               }
                                               catch (Exception ex)
                                               {
                                                   // log ex
                                               }
                                           };
      ...    
}

and I just read that using blocks swallow exceptions. It there an elegant way to handle exceptions from foo1(), foo2() and foo3() in foo(). I don't want to have a try/catch inside of each using block in the methods. I did stumble into this post where an extension method is suggested but I'm just checking to see if there is anything better.

FYI, Network disconnection causes the logic inside the using block to throw an exception and that's what I'm trying to handle in one common place.

Thanks,

10
  • 7
    What on earth are you talking about? Using does not block exceptions. It interacts with exceptions in the sense that using places an implicit try..finally around the statement block, but using does not kill exceptions raised within the statement block. Commented Jun 23, 2011 at 17:16
  • 2
    I think your problem is that it's your background worker thread throwing the exception and you don't have anything checking in on that to bubble it up to your main thread. Your using block shouldn't have anything to do with it. However, I'm making some assumptions here as well. A using block is just syntactic sugar for creating an IDisposable variable, running code, then calling Dispose() on that object at the end if I recall correctly. Commented Jun 23, 2011 at 17:16
  • @SethO the msdn page states that the compiler translates using to a try-finally block where the finally block calls Dispose() but there is no catch block so any exceptions that may be thrown are lost. Commented Jun 23, 2011 at 17:17
  • 5
    @TheOtherGuy try/finally without a catch still throws the exception, it just executes finally before throwing it. Commented Jun 23, 2011 at 17:18
  • 1
    @Jaxidian but the exception does not bubble up to my catch block (even if it's not in backgroundworker's thread). see the linked post that has an example to prove it digitallycreated.net/Blog/51/… Commented Jun 23, 2011 at 17:20

3 Answers 3

4

I think I understand the confusion. Here's some pseudo-code (it may actually execute?) explaining your scenario more simply:

public class Foo
{
    public void DoStuff()
    {
        using (var x = new Thing())
        {
            throw new ApplicationException("This code breaks");
        }
    }

    private class Thing : IDisposable
    {
        public override Dispose()
        {
            throw new ApplicationException("Help, I can't dispose!");
        }
    }
}

This code can be thought of as the same as this code:

public class Foo
{
    public void DoStuff()
    {
        var x = new Thing();
        try
        {
            throw new ApplicationException("This code breaks");
            x.Dispose();
        }
        catch (Exception err)
        {
            x.Dispose();
            rethrow;
        }
    }

    private class Thing : IDisposable
    {
        public override Dispose()
        {
            throw new ApplicationException("Help, I can't dispose!");
        }
    }
}

By using a using block, you are essentially saying, "No matter what you do, execute Dispose() on this object before moving on." However, the using block doesn't gracefully handle the case when Dispose() fails. Because of this, it never gets around to throwing the inside exception because there was another exception that pre-empted it, even if it occurred afterwards.

Does this make sense? Did I even answer your question? I'm not sure if you're looking for help understanding this or what.

Sign up to request clarification or add additional context in comments.

7 Comments

Does a using block even have a catch? I thought it was just a try/finally.
Actually I understand what's going on. In my case I'm using SqlDataReader's Dispose() so there is no rethrow or any exception thrown. I'm trying to see if there is a way to detect the failure in the caller.
@0A0D: No but I was being a bit verbose to emphasize how to expect it to act. When that finally block executes code that in turn throws an exception, well, you don't get all of that finally block's code to execute because an exception is thrown midway through it. This post was not meant to show what code it generates but rather to show how it acts and to emphasize that point.
@TheOtherGuy: Then I would say the "best" way (easiest to read/maintain code without over-architecting a solution, although this is very much a judgement call and I'm far to ignorant to make that judgement for you) is that you should not use using blocks but rather roll your own try/catch/finally blocks so you can more more explicit in how you want it to react (perhaps with try/catch blocks inside your own finally block.
According to Framework Design Guidelines: "AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted." And, since Dispose() should delegate to Dispose(true)...
|
2

My fear is that Microsoft went down the same rabbit hole here as they did with WCF.

See Avoiding Problems with the Using Statement.

Maybe they should follow their own guidelines.

In almost every (other) case a using block is a best practice.

Comments

0

Youcan try this code to bubble-up and exception from a using statement

Exception exc = null;
using (var x = new object())
{
    try
    {
       // do something x, that causes an exception to be thrown
    }
    catch(Exception ex) { exc = ex; } // bubble-up the exception
 }
 if(exc != null) { throw exc; } // throw the exception if it is not null

5 Comments

This would work fine, except for the fact that Object doesn't implement IDisposable, and can thus not be used in a using statement, and your rethrowing in this fashion will mess up the stack trace.
x = new object() ; you can replace new object() with the correct class and parameters. Also, the stack trace will be intact ... as you can read the stack trace as given by the top-level exception or check the inner exception. You can even call GetBaseException(), etc.
I don't see the point of catching an exception in a using statement, only to rethrow it afterwards. Why not refrain from handling it entirely, as the net result will bhe exactly the same?
No because generally an exception thrown in a using statement is often hidden and that is based on observed behavior.
Interesting. I've personally never had this happen to me, which is why the rethrow seems useless to me, but if there are situations where Exceptions don't propagate as they should, then, yeah, this may work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.