15

Is there any difference between these two code samples and if not, why does using exist?

StreamWriter writer;
try {
    writer = new StreamWriter(...)
    writer.blahblah();

} finally {
    writer.Dispose();
}

vs:

using (Streamwriter writer = new Streamwriter(...)) {
    writer.blahblah
}

I mean in the second example you really should be putting it in a try block anyway so adding the finally block really doesn't use much more effort. I get that the entire thing might be encompassed in a bigger try block but yeah, just seems superfluous to me.

Jason Capriotti
  • 1,836
  • 2
  • 17
  • 33
rollsch
  • 2,518
  • 4
  • 39
  • 65
  • 3
    _"you really should be putting it in a try block anyway "_ Why? You could allow any exceptions to bubble up to the top of the stack and leave a clear message and stack trace in a log. – Tim Schmelter Dec 20 '13 at 12:21
  • The same could be said about `foreach`, which is just a somewhat more concise version of calling the iterator methods and properties. – O. R. Mapper Dec 20 '13 at 12:21
  • Your try/finally sample is defective, the using(){} block will work correctly. – H H Dec 20 '13 at 12:36
  • I keep hearing that when an exception throws during execution of Dispose method, the `Using` statement doesn't seem to be useful in par with `Try-Finally` block. I also see [this MSDN](http://msdn.microsoft.com/en-us/library/aa355056(v=vs.110).aspx) article saying the same with a WCF client. – Narayanan Jul 03 '14 at 06:15

6 Answers6

17

There're some issues with your code. Please, never write like this (put using instead), and that's why:

StreamWriter writer;
try {
    // What if you failed here to create StreamWriter? 
    // E.g. you haven't got permissions, the path is wrong etc. 
    // In this case "writer" will point to trash and
    // The "finally" section will be executed
    writer = new StreamWriter(...) 
    writer.blahblah();
} finally {
    // If you failed to execute the StreamWriter's constructor
    // "writer" points to trash and you'll probably crash with Access Violation
    // Moreover, this Access Violation will be an unstable error!
    writer.Dispose(); 
}

When you put using like that

  using (StreamWriter writer = new StreamWriter(...)) {
    writer.blahblah();
  }

It's equal to the code

StreamWriter writer = null; // <- note the assignment

try {
  writer = new StreamWriter(...); 
  writer.blahblah();
}
finally {
  if (!Object.ReferenceEquals(null, writer)) // <- ... And to the check
    writer.Dispose();
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • why used `Object.ReferenceEquals(null)` instead of just `!=null` ? here answer: https://stackoverflow.com/a/51795257/2377343 – T.Todua Jun 09 '20 at 11:05
  • 1
    @T.Todua Why `!=null` instead of just `writer?.Dispose()`? The answer to my question is the same as it is to yours: The language evolves. Especially the over 6.5 years since the Dmitry wrote his answer ;-) – Jay Allen Sep 05 '20 at 04:29
  • Wouldn't using `using() {}` put the `new` statement outside the top of the `try`, thus avoiding the possibility of `null`? In any case, I'm not sure how the possibility of nasty recursion during `==` operator overloading has anything to do with my normal coding practices of whether to use `x == null` or not. It should always be obvious that operator overloading is dicey and probably unnecessary in just about all cases. Too much sugar isn't good for you, even "syntactic sugar". – ebyrob Jan 24 '23 at 16:51
9

Is there any difference between these two code samples

Yes, using checks for null before calling Dispose (i.e. the actual code it is expanded to introduces a null check).

why does using exist?

Because the code is more concise. Just a syntactic sugar.

ken2k
  • 48,145
  • 10
  • 116
  • 176
6

What you've written is pretty much the pattern that using wraps up. And therefore that is the point of using to save having to write the same try....finally block every time you use a Disposable object.

As for your edited question

[...] in the second example you really should be putting it in a try block anyway so adding the finally block really doesn't use much more effort

Chances are you cant (or dont want to) handle that error from blahblah explicitly and you just want it to bubble up to the calling code... but still cleaning up your StreamWriter resources along the way!

So you would end up with this:

StreamWriter writer;
try{
    writer = new StreamWriter(...)
    writer.blahblah();
}catch{
  throw; // pointless!
} finally [
    writer.Dispose();
}
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • _So you would end up with this_ --> why would you do that? `finally` won't swallow the exception, so it is not required at all to throw it explicitly if you just want to exception to bubble up to the calling code. – ken2k Dec 20 '13 at 12:33
  • The OP stated that they are going to put a `try..catch` anyway, that was just a contrived example as to why you may not need to. – Jamiec Dec 20 '13 at 13:10
  • The latter pattern might not be useless if the `catch` block makes note of the exception that occurred, and the `finally` block adjusts its handling of `Dispose`-related problems based upon whether the original `try` block was exited normally or via exception. – supercat Dec 22 '13 at 20:14
1

First of all, using using is safer than your code - it properly handles errors in the Disposable object construction, and will not call dispose on a null object.

The second difference is in code readability - look at your example. The first version takes 7 lines. The second - only 3.

Dariusz
  • 21,561
  • 9
  • 74
  • 114
  • Unfortunatelly, the real difference is not just in code readability. If an exception is thrown in StreamWriter constructor the "try {} catch {}" will crash with floating Access Violation; while "using {}" will do correctly. – Dmitry Bychenko Dec 20 '13 at 12:38
  • That's what the first paragraph is about. But I will rewrite it, since it is apparently unclear. – Dariusz Dec 20 '13 at 12:40
1

The latter is just syntactic sugar for the former. They should do the same thing, but the latter requires less boilerplate code.

I would recommend using the using one as one is less likely to make a mistake.

BambooleanLogic
  • 7,530
  • 3
  • 30
  • 56
  • 2
    Unfortunately, the later is not just a syntactic sugar for the former. There's a subtle difference: if, in the former, an exception is thrown in StreamWriter constructor the code will crash with floating AccessViolation, while later (that is "using{...}") will do correctly – Dmitry Bychenko Dec 20 '13 at 12:45
1

They're not entirely the same. The try/finally block does not protect against silly mistakes.

StreamWriter writer = new StreamWriter(...);
try {
  ...
  writer = new StreamWriter(...);
  ...
} finally {
  writer.Dispose();
}

Note that only the second writer gets disposed. In contrast,

using (StreamWriter writer = new StreamWriter(...)) {
  ...
  writer = new StreamWriter(...);
  ...
}

will give a compile-time error.