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,

  • 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. – dthorpe Jun 23 '11 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. – Jaxidian Jun 23 '11 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. –  Jun 23 '11 at 17:17
  • 5
    @TheOtherGuy try/finally without a catch still throws the exception, it just executes finally before throwing it. – Jaxidian Jun 23 '11 at 17:18
  • @TheOtherGuy - I apologize; I missed the second link before I commented. I am reading up on this now. Interesting question. – SethO Jun 23 '11 at 17:19
  • 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 http://www.digitallycreated.net/Blog/51/c#-using-blocks-can-swallow-exceptions –  Jun 23 '11 at 17:20
  • @TheOtherGuy This still makes sense to me although after reading that post more, my comment about threads is no longer valid. I think of it like this order of events: #1) Instantiate IDisposable #2) Using block throws exception #3) Finally method stops that exception momentarily until it's done but then throws an exception of its own #4) Finally block's exception gets thrown and bubbled up because you said "no matter what, dispose this before you do anything else" and it couldn't do this. For this (and many other) reasons, you need to make sure your Dispose() is very solid/robust code. – Jaxidian Jun 23 '11 at 17:25
  • @Jaxidian I'm using a `SqlDataReader` so it's not my own `Dispose()`. I understand the mechanism and it kinda makes sense but I'm just checking to if there is any workaround/alternative that people usually use. –  Jun 23 '11 at 17:29
  • @TheOtherGuy: What about rolling out the using's into try/finally's? –  Jun 23 '11 at 17:36
  • @0A0D that would be an option but if I think I'll be better off doing try/catch inside of each `using` to take advantage of `using`'s finally block. –  Jun 23 '11 at 17:41

3 Answers3

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.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Jaxidian
  • 13,081
  • 8
  • 83
  • 125
  • 2
    Does a using block even have a catch? I thought it was just a try/finally. –  Jun 23 '11 at 17:37
  • 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. –  Jun 23 '11 at 17:39
  • @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. – Jaxidian Jun 23 '11 at 17:40
  • @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. – Jaxidian Jun 23 '11 at 17:43
  • @TheOtherGuy: You can also stack using statements, which may work in your case. –  Jun 23 '11 at 17:46
  • I guess I'll skip using `using` in this case then. I was hoping there would be a work-around so I could keep the `using`s but I guess not. Thanks guys!. –  Jun 23 '11 at 17:48
  • 1
    According to [Framework Design Guidelines](http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613): "**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)... – TrueWill Jun 23 '11 at 18:00
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.

Community
  • 1
  • 1
TrueWill
  • 25,132
  • 10
  • 101
  • 150
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
NeoH4x0r
  • 311
  • 2
  • 6
  • 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. – Tom Lint May 22 '13 at 08:45
  • 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. – NeoH4x0r Aug 17 '13 at 13:20
  • 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? – Tom Lint Feb 02 '15 at 19:04
  • No because generally an exception thrown in a using statement is often hidden and that is based on observed behavior. – NeoH4x0r Nov 07 '15 at 13:22
  • 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. – Tom Lint Nov 10 '15 at 13:35