66

This was a telephone interview question I had: Is there a time when Dispose will not be called on an object whose scope is declared by a using block?

My answer was no - even if an exception happens during the using block, Dispose will still be called.

The interviewer disagreed and said if using is wrapped in a try-catch block then Dispose will not be called by the time you enter the catch block.

This goes contrary to my understanding of the construct, and I haven't been able to find anything that backs up the interviewers point of view. Is he correct or might I have misunderstood the question?

danronmoon
  • 3,814
  • 5
  • 34
  • 56
AdamCrawford
  • 4,968
  • 1
  • 18
  • 12
  • 10
    The interviewer is wrong; don't take the job! Not least, do you want to work for someone who likes to leave landmines around? – Jeremy McGee Sep 29 '11 at 09:45
  • You should feel lucky if you didn't pass the interview :) – Cheng Chen Sep 29 '11 at 09:47
  • 7
    If you have the interviewers email address, email him back and show him the code that demonstrates that the dispose is called. If he's not impressed don't work for him :) – AndrewC Sep 29 '11 at 09:47
  • 9
    Take the job ! They need you there ! – VdesmedT Sep 29 '11 at 09:58
  • Damn! Some excellent responses there. Hard to know who to mark as the best answer actually as they're all good. As for the job, the RC hasn't gotten back to me with feedback yet but I've already taken a contract I feel much better about, but thanks to the comments above too. – AdamCrawford Sep 29 '11 at 12:48
  • Decided to go with the code sample that specifically disproves the interviewer, rather than the great corner cases where Dispose may not actually be called. – AdamCrawford Sep 29 '11 at 12:51
  • 8
    Perhaps you were interviewed by the same guy Alex Papadimoulis was interviewed by? http://thedailywtf.com/Articles/My-Tales.aspx – Eric Lippert Sep 29 '11 at 14:55
  • Not in line with your actual question, but exception filters (not available in C#, but bizarrely available in VB) let you run some "outer" code after the exception is thrown, but before the finally block takes effect. – Damien_The_Unbeliever Sep 29 '11 at 18:11
  • 3
    EMP would do it. General power loss could too. – dotjoe Sep 29 '11 at 19:02
  • 2
    Maybe he was trying to see how you handle ignorant stubborn colleagues... – Niklas Oct 05 '11 at 16:23
  • Unhandled exception in other thread: http://stackoverflow.com/questions/5777204/multithreading-exception-and-dispose-why-dispose-didnt-call – Tim Abell Apr 26 '12 at 08:16
  • @Damien_The_Unbeliever: Even if one doesn't like certain aspects of exception-filtering semantics, there are a number of things that can only be done with exception filters, which a language could provide for without exposing the worse aspects. Among then, allowing e.g. `catch (Exception ex) where ex:ThisException, ThatException` [obvious meaning] or `finally (Exception ex)` [would behave as a `finally` block, but with `ex` being set to the exception, if any, that will be thrown when the `finally` block completes, or `null` if none; useful e.g. in factory functions that return `IDisposable`]. – supercat Apr 29 '13 at 18:52
  • @Damien_The_Unbeliever: It's too bad C# doesn't allow for any such things, and even vb.net doesn't really make them convenient. I don't think those features would add any "dangers" to the language, but would expose two of the more useful aspects of filters. – supercat Apr 29 '13 at 18:56

8 Answers8

58

Four things that will cause Dispose to not be called in a using block:

  1. A power failure on your machine when inside the using block.
  2. Your machine getting melted by an atomic bomb while in the inside of the using block.
  3. Uncatchable exceptions like StackOverflowException, AccessViolationException and possibly others.
  4. Environment.FailFast
Community
  • 1
  • 1
Øyvind Bråthen
  • 59,338
  • 27
  • 124
  • 151
  • 18
    Listed in order of probability ;) – serega Sep 29 '11 at 10:05
  • 1
    Should we mark every using block with a 'Radioactive Hazard' sign because of #2? Please advice!!!!1111 http://en.wikipedia.org/wiki/File:Radioactive.svg – IgorK Sep 29 '11 at 10:45
  • Stackoverflow exception - great example! – AdamCrawford Sep 29 '11 at 12:53
  • Don't forget the entire VM crashing, it has happened before (specifically back in 3.5 with some configurations under x64). – Blindy Sep 29 '11 at 15:14
  • 6
    4. Environment.Failfast listed below. http://msdn.microsoft.com/en-us/library/ms131100.aspx – WernerCD Sep 29 '11 at 17:54
  • 1
    Perhaps even ExecutionEngineException will break the finally block, but it's quite complex to test :-) – xanatos Sep 30 '11 at 11:58
  • Another you forgot: `using (var thing = new DisposableThing())` will not clean up `DisposableThing` if its constructor throws. Not that there's any way the `using` statement could clean it up, but unfortunately there's no particularly nice pattern via which `DisposeableThing` can ensure its own cleanup either. Worse, it's almost impossible for disposable base class to ensure cleanup if the constructor for a derived class written in vb.net or C# throws an exception [C++/CLI will automatically `Dispose` the partially-constructed object, but vb.net and C# all but force its abandonment]. – supercat Apr 29 '13 at 19:01
53
void Main()
{
    try
    {
        using(var d = new MyDisposable())
        {
            throw new Exception("Hello");
        }
    }
    catch
    {
        "Exception caught.".Dump();
    }

}

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

This produced :

Disposed
Exception caught

So I agree with you and not with the smarty interviewer...

Andrew
  • 291
  • 1
  • 10
VdesmedT
  • 9,037
  • 3
  • 34
  • 50
  • 5
    Why is this the accepted answer? This isn't how science works, you don't just pick a specific, tailor-made example and declare your theory perfect... In case you're wondering, you are in fact completely wrong, it is possible for `Dispose` not to get called. – Blindy Sep 29 '11 at 15:11
  • 7
    @blindy: Wouaw, that really pissed you off, sorry. Are you hiring ;-) – VdesmedT Sep 29 '11 at 15:17
  • http://en.wikipedia.org/wiki/Scientific_method have a read before mocking... And no, I don't think I'd hire you. – Blindy Sep 29 '11 at 15:18
  • 29
    @Blindy "The interviewer disagreed and said *if using is wrapped in a try catch block then Dispose will not be called by the time you enter the catch block.*" I think the answer is a pretty good counterexample to the interviewer's "theory". – anton.burger Sep 29 '11 at 15:49
  • 2
    Forgive me but what is .Dump() on the strings? – HitLikeAHammer Sep 29 '11 at 23:00
  • 1
    @HitLikeAHammer - It's an extension method used by LINQPad to output whatever your are "dumping". – Øyvind Bråthen Sep 30 '11 at 05:12
  • 1
    @Blindy: I find it ironic that you call the answer unscientific, yet you do not disprove it by showing a counter example. I'm interested in the situation you claim exists; *can you* provide an answer that demonstrates what you claim? –  Oct 05 '11 at 13:48
  • 3
    @Will, Øyvind did that for me, why retype it? And I never tried to *prove* it is possible for `Dispose` not to get called, VdesmedT did, and he tried it by choosing a *working* example. My point, I believe, stands. – Blindy Oct 05 '11 at 13:56
  • 2
    @Blindy: Pfft. Spare me your haughty links to wikipedia's definition of the scientific method. Saying that you can disprove a fact because, halfway through the proof a meteor may smash through the ceiling and disrupt the experiment, is about as ridiculous as you can get. And I can't see anywhere that *VdesmedT did, and he tried it by choosing a working example.* Again, I ask if you can please give me an example of where this might happen (not including any where Godzilla is involved)? –  Oct 05 '11 at 14:01
  • 1
    The Stackoverflow exception is not involving Godzilla and indeed make the Dispose method not being called. (even if as far as the process is concerned, Godzilla or Stackoverflow exception are about the same). Still, those cases exists: everything that makes the process blowing does not call Dispose either. Thank you Blindy for holding so hard. – VdesmedT Oct 05 '11 at 14:21
25

Bizarrely I read about a circumstance where Dispose won't get called in a using block just this morning. Checkout this blog on MSDN. It's around using Dispose with IEnumerable and the yield keyword, when you don't iterate the entire collection.

Unfortunately this doesn't deal with the exception case, honestly I'm not sure about that one. I would have expected it to be done but maybe it's worth checking with a quick bit of code?

Ian
  • 33,605
  • 26
  • 118
  • 198
  • 7
    The behavior described in the post is very logical. Dispose in an iterator (yield) method will not get called if the consumer of the returned iterator does not call `Dispose` on that `IEnumerator`. Or in other words: "Dispose won't get called in cases you don't call Dispose", which is of course trivial. The solutions: wrap the usage of an `IEnumerator` in a using block, or iterate it using the C# `foreach` statement. – Steven Sep 29 '11 at 09:48
21

The other answers about power failure, Environment.FailFast(), iterators or cheating by using something that is null are all interesting. But I find it curious that nobody mentioned what I think is the most common situation when Dispose() won't be called even in the presence of using: when the expression inside using throws an exception.

Of course, this is logical: the expression in using threw an exception, so the assignment didn't take place and there is nothing we could call Dispose() on. But the disposable object can already exist, although it can be in half initialized state. And even in this state it can already hold some unmanaged resources. This is another reason why correctly implementing the disposable pattern is important.

Example of the problematic code:

using (var f = new Foo())
{
    // something
}

…

class Foo : IDisposable
{
    UnmanagedResource m_resource;

    public Foo()
    {
        // obtain m_resource

        throw new Exception();
    }

    public void Dispose()
    {
        // release m_resource
    }
}

Here, it looks like Foo releases m_resource correctly and we are using using correctly too. But the Dispose() on Foo is never called, because of the exception. The fix in this case is to use finalizer and release the resource there too.

svick
  • 236,525
  • 50
  • 385
  • 514
  • 4
    +1 Very nice catch. Actually, I would say the "fix" is to not allowcate unmanaged resources in the ctor at all. All access to such resources should be done using lazy loading. – Sunny Milenov Sep 30 '11 at 18:29
  • First time I learned an argument for not initializing an object in constructor. Everything I know about [RAII](http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Resource_Acquisition_Is_Initialization) is wrong :( – Miserable Variable Oct 05 '11 at 19:06
  • 1
    @HemalPandya, I think RAII is much more important in C++, because it doesn't have a garbage collector or `using`. But I don't think this is an argument against initialization in constructor. It's more an argument for properly implementing finalizer, if you need it. – svick Oct 05 '11 at 19:09
  • But finalizer is only good for Unmanaged Resources right? What do you do about managed resources which were initialized in the constructor? Is it better not to let exception escape from an IDisposable constructor? – Miserable Variable Oct 05 '11 at 19:22
  • 1
    There is no need to release managed resources in finalizer, because they will be (or, possibly, already have been) GCed. And if they, in turn, own some unmanaged resources, they should take care of them in their finalizers. – svick Oct 05 '11 at 19:34
  • 1
    This answer is especially interesting because it may mean that the interviewer is somewhat right. I disagree on the fix, I would prefer that if the constructor can throw that resources should be released in a catch block in the constructor and the exception rethrown, because there is no guarantee on if/when your finalizer is going to be called. – Yaur Nov 16 '11 at 12:38
  • This answer relates to what is IMHO a flaw in .net languages, which is that there is no clean way for a class to ensure that `Dispose` will get called if a partially-executed constructor throws an exception. It's possible to achieve such a result if one doesn't have any public constructors, and if each derived class includes a factory method that wraps a `try/finally` block around a call to a constructor which takes an `IDisposable` as a ref parameter and stores itself there. – supercat Jun 14 '12 at 22:49
19

The using block gets turned by the compiler into a try/finally block of its own, within the existing try block.

For example:

try 
{
    using (MemoryStream ms = new MemoryStream())
        throw new Exception();
}
catch (Exception)
{
    throw;
}

becomes

.try
{
  IL_0000:  newobj     instance void [mscorlib]System.IO.MemoryStream::.ctor()
  IL_0005:  stloc.0
  .try
  {
    IL_0006:  newobj     instance void [mscorlib]System.Exception::.ctor()
    IL_000b:  throw
  }  // end .try
  finally
  {
    IL_000c:  ldloc.0
    IL_000d:  brfalse.s  IL_0015
    IL_000f:  ldloc.0
    IL_0010:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0015:  endfinally
  }  // end handler
}  // end .try
catch [mscorlib]System.Exception 
{
  IL_0016:  pop
  IL_0017:  rethrow
}  // end handler

The compiler won't rearrange things. So it happens like this:

  1. Exception is thrown in, or propagates to, the using block's try part
  2. Control leaves the using block's try part, and enters its finally part
  3. Object is disposed by the code in the finally block
  4. Control leaves the finally block, and the exception propagates out to the outer try
  5. Control leaves the outer try and goes into the exception handler

Point being, the inner finally block always runs before the outer catch, because the exception doesn't propagate til the finally block finishes.

The only normal case where this won't happen, is in a generator (excuse me, "iterator"). An iterator gets turned into a semi-complicated state machine, and finally blocks are not guaranteed to run if it becomes unreachable after a yield return (but before it has been disposed).

cHao
  • 84,970
  • 20
  • 145
  • 172
  • 1
    The finally happens *after* control leaves the try block. – Eric Lippert Sep 29 '11 at 12:49
  • @Eric: I actually did mean *before*, as i was talking about the outer try rather than the one that `using` generated. But it gets a bit confusing when you're talking about both at once. Hopefully clarified it a bit. – cHao Sep 29 '11 at 14:47
13
using (var d = new SomeDisposable()) {
    Environment.FailFast("no dispose");
}
adrianm
  • 14,468
  • 5
  • 55
  • 102
  • 3
    Would be nice if you had more information included: http://msdn.microsoft.com/en-us/library/ms131100.aspx – WernerCD Sep 29 '11 at 17:54
5

Yes there is a case when dispose won't be called... you are over thinking it. The case is when the variable in the using block is null

class foo
{
    public static IDisposable factory()
    {
        return null;
    }
}

using (var disp = foo.factory())
{
    //do some stuff
}

will not throw an exception but would if dispose was called in every case. The specific case that your interviewer mentioned is wrong though.

Yaur
  • 7,333
  • 1
  • 25
  • 36
0

The interviewer is partially right. Dispose may not correctly clean up the underlying object on a case-by-case basis.

WCF for example has a few known issues if an exception is thrown while in a using block. Your interviewer was probably thinking of this.

Here is an article from MSDN on how to avoid issues with the using block with WCF. Here is Microsoft's official workaround, although I now think that a combination of that answer and this one is the most elegant approach.

Community
  • 1
  • 1
makerofthings7
  • 60,103
  • 53
  • 215
  • 448