Search code examples
.netgarbage-collectiondispose

C# - idea behind instantiating BitMap object twice to avoid locking problems


I had a problem with deleting image that was opened in a PictureBox. Thanks to Hans Passant I got a solution for this problem using this snippet proposed by him :

            using (var temp = new Bitmap(openFileDialog1.FileName))
            {
                pictureBox1.Image = new Bitmap(temp);
            }

I tried to crash the code but I couldn't so it seems to work, but I don't quite understand the logic behind this code. Before I was doing :

if (MyImage != null)
                    {
                        MyImage.Dispose();

                    }
...
MyImage = new Bitmap(openFileDialog1.FileName);
                    pictureBox1.Image = (Image)MyImage;

which even very rare caused a problem with resource being used.

Why this not happen in the new code that I'm using. I ask this in order to understand what happens under the cover. I know that using guarantees that Dispose() will be called but Disposed() is called in the previous code as well. Most of the time the resource is released fast enough but what what is the big difference that allows the new code to release the image always fast enough so it could be deleted or whatever we need to do with it?


Solution

  • When you create a Bitmap object from a file, it will keep the file open as long as the Bitmap object exists.

    In your original code you are using the Bitmap object opened from the file in the control, so as long as the control shows the image, the file will be open.

    In the new code a new Bitmap object is created by copying the data from the Bitmap object that was created from the file. The new Bitmap object doesn't copy the connection to the file, so when you dispose the first Bitmap object the file will be closed.

    A solution that uses a bit less resources would be to read the data from the file into a byte array, create a memory stream from that and use that to create the image:

    using (var m = new MemoryStream(File.ReadAllBytes(openFileDialog1.FileName))) {
      pictureBox1.Image = Image.FromStream(m);
    }