2

I was reading a forum recently, and saw this comment:

So, you see you've been duped into believing that the 'using' syntax is going to help clean up your resources for you. Oh well, welcome to .NET development.

This has really freaked me out! I use using almost exclusively over .Dispose() in nearly all cases (streams especially). Is there some weird thing with "using" that no one has told me? Is it good or bad or indifferent to use?

Ash
  • 24,276
  • 34
  • 107
  • 152

10 Answers10

15

From MSDN:

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

is translated into the following by the compiler:

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

so not sure what you're worrying about.

Edit: Be warned though, if you are using the using pattern on your own types, the pattern will only be as effective as your Dispose() method. Some of the comments and other answers this.

Szymon Rozga
  • 17,971
  • 7
  • 53
  • 66
  • I agree, I think it does exactly what we're lead to believe it does. – Ray Hidayat May 18 '09 at 02:31
  • Huh, I thought they'd changed the 'finally' code in the pattern, because that could could throw an exception if the cast failed, and that it looked more like this: var disp = font1 as IDisposable; if (disp != null) disp.Dispose(); – Joel Coehoorn May 18 '09 at 02:47
  • Yeah, that's excellent - I was very sure it was a-ok - I guess I was just frightened by the comment - I guess I overreacted due to not feeling too well today. Thanks for clearing this up guys. – Ash May 18 '09 at 02:56
  • 3
    How could the cast fail? C# won't let you compile a using() statement wrapping a variable that doesn't implement IDisposable. – mqp May 18 '09 at 03:06
  • 1
    Yes, but using is only as good as your Dispose. If your object allocates non-managed resources, but does not handle them properly in Dispose, you can still have a problem. – JP Alioto May 18 '09 at 03:22
  • JP: You bring up an incredibly important point. I edited the answer to reflect this. – Szymon Rozga May 18 '09 at 11:12
7

There are some cases where using will not clean up as you might expect, such as:

using (var myObject = new DisposableObject().AnotherDisposable())
{
    //Do things to myObject
}

In this example you have two objects, DisposableObject and AnotherDisposable and the using will only clean up AnotherDisposable and leave DisposableObject leaking.

Jon Cahill
  • 4,968
  • 4
  • 34
  • 31
  • Interesting example. Technically the using statement is still perfoming as expected -- although it's pretty clear it's not what the desired. I'm not sure how they could have accounted for that in the design of the using statemen. Simple rule: one using block one Dispose method call no more no less. – Ralph Shillington May 18 '09 at 02:42
  • I agree, using is working as specified and there is no way to really account for it, but it is something to be aware of! – Jon Cahill May 18 '09 at 02:45
  • 2
    Eh: I take that as a code smell, in that you shouldn't really create a disposable object without disposing it. At best, it's misleading. This would be better, because it will get both: using (var parent = new DisposableObject(), myObject = parent.AnotherDisposable()) {} – Joel Coehoorn May 18 '09 at 02:50
  • I agree with Joel....that's a desperate example and should be avoided by its code smell, else one deserves the result. – kenny May 18 '09 at 11:20
3

It would help if you could provide us with a link to the context; but, generally, that kind of mostly-attitude opinion without backup should be taken with a healthy grain of salt.

overslacked
  • 4,127
  • 24
  • 28
3

Yes, it does do what you'd expect it to do. If you have a look at the IL of a "using" statement this is what you get:

L_0007: newobj instance void Demo.SomeClass::.ctor()
L_000c: stloc.0 
L_000d: nop 
...
L_0040: nop 
L_0041: nop 
L_0042: leave.s L_0054
L_0044: ldloc.0 
L_0045: ldnull 
L_0046: ceq 
L_0048: stloc.2 
L_0049: ldloc.2 
L_004a: brtrue.s L_0053
L_004c: ldloc.0 
L_004d: callvirt instance void [mscorlib]System.IDisposable::Dispose()

(I stipped out the stuff from within my using statement to condense a bit, but you get the idea)

Aaron Powell
  • 24,927
  • 18
  • 98
  • 150
1

'Using' is a pattern. Sometimes your code flows with the pattern and sometimes it doesn't. Meaning that sometimes you have to actually call dispose because your object doesn't fit the 'using' pattern's scope.

As an example, if you instance an object upon application startup and then need to dispose of it in the middle of the application and instance a new one, chances are you can't use 'using.'

user79755
  • 2,623
  • 5
  • 30
  • 36
1

It will clean up any resources that the Dispose() method cleans up, because the using(){} construct is just syntactic sugar for calling the Dispose() method.

MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
1

I take it you mean this thread? (thank you google):
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/4b63dc82-c7c0-4495-97ca-d92502a33d15

The using statement will call .Dispose() on any object that implements IDisposable. If the using statement failed to clean up the resources, a call to Dispose() directly would have failed as well. In the specific case that I linked to, it sounds like a mis-behaving virus checker was the problem.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
0

Using is just another way of ensuring the Dispose method is called on your object. As far as any resources not handled by the Dispose method, they will remain for garbage collection so you are still at the mercy of the object you declare in your using statement. I am obviously reading into your comment since you did not post a link to the article you are referring to.

Adam Carr
  • 2,986
  • 7
  • 31
  • 38
0

The end of the using block calls Dispose. Dispose provides the opportunity for the caller to explicitly free unmanaged resources that your object is using. The garbage collector will implicitly free managed resources using the object's Finalizer. But the GC knows nothing about unmanaged resources that you have allocated (file handles, window handles). So, if you allocate unmanaged resources and don't free them properly in your Dispose correctly, you will leak. Using is only as good as your Dispose.

There's much more on garbage collection here and more on Finalize v.s. Dispose in this SO thread.

Community
  • 1
  • 1
JP Alioto
  • 44,864
  • 6
  • 88
  • 112
0

I have seen times where a file was still left open when the application crashed because the using construct was used. It seems that closing connections is not always done when using this. So, when I open files or database connections I explicitly use the try..finally myself.

James Black
  • 41,583
  • 10
  • 86
  • 166
  • 2
    If the application crashed in the middle of the using() block, a try...finally around the same area wouldn't have caught it either. – mqp May 18 '09 at 03:08
  • mquander is right. Again, once compiled, using(){} becomes a try...finally. A crash is a crash; if the crash is severe enough, your finally clause won't execute either. Remember: Microsoft only "guarantees" that finally will execute when there aren't severe conditions (EG, out of memory, hard system failure, etc). – John Rudy May 18 '09 at 11:33
  • When I had the same condition with the try..finally the problem went away. I don't remember what the error was, I was doing this under WindowsCE 5.0. – James Black May 18 '09 at 15:01