Implementing IDisposable C#

2019-03-04 22:55发布

问题:

I'm having a little trouble understanding the IDisposable interface

I'm developing a Game Engine and have ran code analysis on my solution and been told to implement the IDisposable interface on my "GrapicsEngine" class, because it contains a Bitmap instance.

Naturally, I searched the internet to learn how to do this correctly and have came up with the following code:

Here is my class members:

private const int BITMAP_WIDTH = 4096;
private const int BITMAP_HEIGHT = 4096;

private Graphics backBuffer;
private Bitmap bitmap;

private Color clearColor;

private WindowSurface surface;

private GraphicsQuality quality;

private Viewport viewport;

and here is my IDispoable region:

#region IDisposable

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if (disposing == true)
        ReleaseManagedResources();

    ReleaseUnmanagedResources();
}

private void ReleaseManagedResources()
{
    if (bitmap != null)
        bitmap.Dispose();
    if (backBuffer != null)
        backBuffer.Dispose();
}

private void ReleaseUnmanagedResources()
{

}

~GraphicsEngine()
{
    Dispose(false);
}

#endregion

Note that WindowSurface is a WinForm Panel, GraphicsQuality is an enum and Viewport contains only int values.

So I have just a couple questions:

  1. Am I disposing of my resources properly?
  2. What resources should I dispose of in the Unmanaged resources method
  3. If I create a new class and it contains my GraphicsEngine class, should that class also implement IDisposable?

Any help on this topic would be greatly appreciated.

回答1:

You're on the right track. Anytime you have a class level variable that is disposable the containing class should also be disposable. And you're handling it properly from what I can tell. I don't see class name line so I can't tell if you have the IDisposable interface included but I imagine you do since you have implemented the methods. If not make sure you add it.
IDisposable is a chain reaction type of implementation. If the variable is disposable, and it's only local to a method call then you dispose of it at the end of the call, but if it's at the class level you implement IDisposable and dispose of it with your class as you're doing. That way anyone using your class can dispose of it properly.

So for example: Say I have a file open in my class...

public class MyClass
{
     private File txtFile = File.Create(...)
}

Now someone uses my class.

private void useClass()
{
     var myClass = new MyClass();
}

Well, they have just opened a file and it wasn't disposed of properly.

Modify the code and it can be used like so...

public sealed class MyClass : IDisposable
{
     private File txtFile = new File.Create(...)

     public void Dispose()
     {
          txtFile.Dispose();
          GC.SuppressFinalize(this);
     }

     ~MyClass() => Dispose();
}

And when the use it they can use it like so...

private void useClass()
{
     using (var myClass = new MyClass())
     {
         //some code
     }
}

Hopefully this answers your questions. Just remember, is you declare a disposable object local to a method then you don't have to implement IDisposable in your class because you're going to dispose of it in that method. But if you implement it at class level scope, whether you have a method disposing it or not, you should implement IDisposable and check to make sure it's disposed when that containing class calls dispose. Make sense? Hope this helps.



回答2:

I found the simplest way to implement IDisposable

 internal class ConnectionConfiguration : IDisposable
{
    private static volatile IConnection _masterconnection;
    private static readonly object ConnectionLock = new object();
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
        if (_masterconnection == null)
        {
            return;
        }
        lock (ConnectionLock)
        {
            if (_masterconnection == null)
            {
                return;
            }
            _masterconnection?.Dispose();//double check
            _masterconnection = null;
        }
    }
}