Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Icon still usable after calling Dispose()?

Tags:

c#

.net-2.0

I've been trying to sort out some of our code using Dispose properly in a number of places that things were being left hanging around. Once such instance was Icons, and something I noticed which I thought was odd, if I call Icon.Dispose() I was still able to use the Icon.

So I extracted it out into a little console application that I fully expected to crash (throw an ObjectDisposedException), but it didn't... Am I mis-understanding what dispose should be doing here?

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;

namespace DisposeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Icon icon = new Icon(@"C:\temp\test.ico");
            icon.ToBitmap().Save(@"C:\temp\1.bmp");
            icon.Save(new FileStream(@"C:\temp\1.ico", FileMode.OpenOrCreate, FileAccess.ReadWrite));
            icon.Dispose();
            GC.Collect(); // Probably not needed, but just checking.
            icon.Save(new FileStream(@"C:\temp\2.ico", FileMode.OpenOrCreate, FileAccess.ReadWrite));
            icon.ToBitmap().Save(@"C:\temp\2.bmp");
        }
    }
}
like image 918
Ian Avatar asked Aug 16 '11 13:08

Ian


People also ask

What happens if Dispose is not called?

Implement a finalizer to free resources when Dispose is not called. By default, the garbage collector automatically calls an object's finalizer before reclaiming its memory. However, if the Dispose method has been called, it is typically unnecessary for the garbage collector to call the disposed object's finalizer.

Does the garbage collector call Dispose?

The Dispose() method The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

When should you implement a dispose?

If you access unmanaged resources (e.g. files, database connections etc.) in a class, you should implement IDisposable and overwrite the Dispose method to allow you to control when the memory is freed.

How do you use dispose?

How to use Dispose in a sentence. He'd have no reason to remove her body and dispose of it somewhere else. Such perceptions dispose the mind to pursue what nature dictates as useful. Start a compost pile to dispose of food waste.


3 Answers

I extracted it out into a little console application that I fully expected to crash, but it didn't. Am I mis-understanding what dispose should be doing here?

Programs that contain bad programming practices are not required to crash and burn. It sure is nice if they do, but they do not have to. To my knowledge the documentation does not state that "program crashes if you use a disposed icon" is a supported feature of the library, so you cannot rely on it.

(If the documentation does say that somewhere then you've found a bug; if you feel like reporting it on Connect, that would be appreciated.)

For a related question that people seem to find entertaining, see this question about taking advantage of non-crashing behaviour in C:

Can a local variable's memory be accessed outside its scope?

Finally, your comment is correct in noting that the garbage collector is probably not relevant. Remember, the point of "Dispose" is to throw away unmanaged resources. The point of the garbage collector is to throw away managed memory and to throw away unmanaged resources via finalizers. Since the icon's memory is still alive (and the disposer will probably have suppressed finalization regardless), forcing a garbage collection here is unlikely to do anything.

like image 121
Eric Lippert Avatar answered Sep 21 '22 19:09

Eric Lippert


It doesn't crash because the Dispose() method doesn't do anything in your case. The Icon class wrapper can wrap two distinct sources of icon data. In your case, the icon data comes from a file and is stored in a byte[]. Which is not a system resource that requires disposing, the garbage collector already takes care of it.

The other icon data source is from a Windows handle. Fairly rare, but you'll get that when using Icon.FromHandle() or one of the System.Drawing.SystemIcons. Now it does wrap an unmanaged resource that makes using Dispose() useful.

This pattern is not unusual. There are also plenty of cases where Dispose() is inherited into a class where it doesn't make much sense. Like MemoryStream or BackgroundWorker. The conventional wisdom is to dispose them anyway.

like image 40
Hans Passant Avatar answered Sep 20 '22 19:09

Hans Passant


This behaviour, while a little strange-looking, does make some sense. Usually, Dispose() is used to release unmanaged resources; it's a way to "play nice" with other processes in the system. In this case, you're likely releasing the HICON handle during Dispose(). The rest of the (managed) resources associated with the Icon (including the actual byte[] data) will be release when the managed object is collected.

You try to do that by calling GC.Collect(), but that's not going to do anything, since the Icon is still alive: it's referenced by the local variable called icon, and is not currently eligible for collection.

like image 26
dlev Avatar answered Sep 24 '22 19:09

dlev