Using statement on IDisposable object - delay the call to the Dispose method

As this article describes how to use use on IDisposable objects, one interesting thing is said:

... using a block, the Dispose method is automatically called some time after the block completes. (This may not be right away; it depends on the CLR.)

Interestingly, this is " It may not be right away, it depends on the CLR ." Can someone provide more details about this? Since we have some strange situations when it seems that when using the code (new MyDisposable ()) {...} after the end of the block, it does NOT immediately call the Dispose method on the MyDisposable instance, but some later.

UPDATE: Conclusion for me, it seems to me that I have problems elsewhere. I think that the Dispose method can be called some time after using the ends of the block. But when it is not, I have to find the problem somewhere else in my code. Thanks for answers!

+7
c # idisposable using-statement
source share
4 answers

I am a little skeptical about this statement and I think that they had in mind something else (perhaps garbage collection). The using statement is just syntactic sugar for the try / finally block, in which calls to finally blocks are blocked. Given this C #:

using (var fs = new FileStream("C:\\blah.txt", FileMode.CreateNew)) { fs.WriteByte(7); } 

IL is as follows:

 //snipped L_000e: nop L_000f: ldstr "C:\\blah.txt" L_0014: ldc.i4.1 L_0015: newobj instance void [mscorlib]System.IO.FileStream::.ctor(string, valuetype [mscorlib]System.IO.FileMode) L_001a: stloc.0 L_001b: nop L_001c: ldloc.0 L_001d: ldc.i4.7 L_001e: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) L_0023: nop L_0024: nop L_0025: leave.s L_0037 L_0027: ldloc.0 L_0028: ldnull L_0029: ceq L_002b: stloc.1 L_002c: ldloc.1 L_002d: brtrue.s L_0036 L_002f: ldloc.0 L_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose() L_0035: nop L_0036: endfinally L_0037: nop L_0038: nop L_0039: ret .try L_001b to L_0027 finally handler L_0027 to L_0037 

Note that on the last line this is just .try and .finally. This is also stated in the C # spec: http://msdn.microsoft.com/en-us/library/aa664736.aspx

+5
source share
 using (SomeDisposableResource resource = new SomeDisposableResource()) { // TODO: use the resource } 

equivalent to:

 SomeDisposableResource resource = new SomeDisposableResource(); try { // TODO: use the resource } finally { if (resource != null) { ((IDisposable)resource).Dispose(); } } 

so, it's up to you to draw conclusions. It all depends on how you define the immediate. In a multi-threaded environment, other actions may be performed between the try block and the removal of the resource, but since it is wrapped in a finally block, it is guaranteed that Dispose will be called.

+9
source share

Strange ... very strange ...

Perhaps the article is incorrect. The using statement compiled exactly like

 MyDisposableObject obj = new MyDisposableObject() try { obj.Use(); } finally { if (obj!=null) obj.Dispose(); } 

The Dispose method is explicitly called in the finally block, unlike the / Finalize destructor method, which is called before the collection, but at the discretion of GC.

I think this is a mistake in the article. At best ... something could mean scheduling threads. If the CLR decides to schedule other threads, once clicking finally, then you can wait a bit of time on the 100% CPU load and higher priority tasks started to run Dispose.

It is important for Dispose to be synchronous !!! Think About This Managed Resource Example

 public void Log(string message) { using(StreamWriter sw = new StreamWriter(File.Append(path))) { sw.WriteLine(message); } } public static void Main() { Log("Hello"); Log("World"); } 

Calling Dispose , in streams and files, actually closes them. If what was written in the article was true, you would call the second Log with an open file , thereby immediately raising an IOException !

+1
source share

I don’t know where it came from, and it contradicts everything that I saw in the using statement, for example in this article , which says that the using block looks like this:

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

performed as follows:

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

So, the Dispose method is called before the next statement following the using block.

The person writing the article may be confused by the way the object will collect garbage some time after it is no longer used, or as disposable objects that are not located, have their finalizer called by the background thread.

0
source share

All Articles