Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Instead of thinking of this as a special class implementing <code>IDisposable</code>, think of what it would be like in terms of normal program flow:</p> <pre><code>Directory dir = Directory.CreateDirectory(path); try { string fileName = Path.Combine(path, "data.txt"); File.WriteAllText(fileName, myData); UploadFile(fileName); File.Delete(fileName); } finally { Directory.Delete(dir); } </code></pre> <p>How should this behave? It's the exact same question. Do you leave the content of the <code>finally</code> block as-is, thereby potentially masking an exception that occurs in the <code>try</code> block, or do you wrap the <code>Directory.Delete</code> in its own <code>try-catch</code> block, swallowing any exception in order to prevent masking the original?</p> <p>I don't think there's any <em>right answer</em> - the fact is, you can only have one ambient exception, so you have to pick one. However, the .NET Framework does set some precedents; one example is WCF service proxies (<code>ICommunicationObject</code>). If you attempt to <code>Dispose</code> a channel that is faulted, it throws an exception and <em>will</em> mask any exception that is already on the stack. If I'm not mistaken, <code>TransactionScope</code> can do this too.</p> <p>Of course, this very behaviour in WCF has been an endless source of confusion; most people actually consider it very annoying if not broken. Google "WCF dispose mask" and you'll see what I mean. So perhaps we shouldn't always try to do things the same way Microsoft does them.</p> <p>Personally, I'm of the mind that <code>Dispose</code> should never mask an exception already on the stack. The <code>using</code> statement is effectively a <code>finally</code> block and <em>most of the time</em> (there are always edge cases), you would not want to throw (and not catch) exceptions in a <code>finally</code> block, either. The reason is simply debugging; it can be <em>extremely</em> hard to get to the bottom of an issue - especially an issue in production where you can't step through the source - when you don't even have the ability to find out where exactly the app is failing. I've been in this position before and I can confidently say that it will drive you completely and utterly insane.</p> <p>My recommendation would be either to eat the exception in <code>Dispose</code> (log it, of course), or actually check to see if you're <a href="http://geekswithblogs.net/akraus1/archive/2008/04/08/121121.aspx" rel="noreferrer">already in a stack-unwinding scenario due to an exception</a>, and only eat subsequent exceptions if you know that you'll be masking them. The advantage of the latter is that you don't eat exceptions unless you really have to; the disadvantage is that you've introduced some non-deterministic behaviour into your program. Yet another trade-off.</p> <p>Most people will probably just go with the former option and simply hide any exception occurring in <code>finally</code> (or <code>using</code>).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload