Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement IDisposable interface in a class inherited from SocketAsyncEventArgs

I work on a huge project in C# .NET 4.0. There is a custom class inherited from System.Net.Sockets.SocketAsyncEventArgs class. Something like the following:

public class SocketTaskArgs : SocketAsyncEventArgs
{
    public SocketTaskArgs()
    {
        Completed += someEventhHandler;
    }

    public void CleanUp()
    {
        Completed -= someEventhHandler;
    }

    /* 
        There is a lot of code here that is unimportant at the moment.
    */
}

So, I wanted to move the content of CleanUp() method to Dispose(bool) method.

As first, I checked the source code of the base class - SocketAsyncEventArgs (using Go To Definition so that I saw metadata as source). I found out, this class implements IDisposable interface. Nice, I just need to override the Dispose(bool) method, don't I? (See IDisposable Interface on MSDN, the "IDisposable and the inheritance hierarchy" section, for more details). Nothing new for me... Unfortunately, the SocketAsyncEventArgs class is implemented as following:

public class SocketAsyncEventArgs : EventArgs, IDisposable
{
    public void Dispose();

    //some other stuff here
}

That means, there is no way how to override Dispose(bool) method, as it's implemented as private instead of protected... What is the reason for this?

Next, I read about SocketAsyncEventArgs.Dispose() method on MSDN. The funny thing is that, it contains the following section:

Notes to Inheritors

Dispose can be called multiple times by other objects. When overriding Dispose(Boolean), be careful not to reference objects that have been previously disposed of in an earlier call to Dispose. For more information about how to implement Dispose(Boolean), see Implementing a Dispose Method.

Wait... what?

When overriding Dispose(Boolean), ...

How am I supposed to override Dispose(Boolean)?

What is the recommended way to implement IDisposable interface in this case?

like image 545
Marek Takac Avatar asked Sep 27 '22 06:09

Marek Takac


1 Answers

There doesn't seem to be anything stopping you from implementing IDisposable on your child class, take this example:

public class DisposableParent : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("The parent was disposed.");
    }
}

public class DisposableChild : DisposableParent, IDisposable
{
    public new void Dispose()
    {
        base.Dispose();
        Console.WriteLine("The child was disposed.");
    }
}

public class Program
{
    public static void Main()
    {
         using (DisposableChild c = new DisposableChild()) { }
         Console.ReadKey(true);
    }
}

Gives the following output:

The parent was disposed.

The child was disposed.

The compiler warns about hiding the dispose of the parent class in the child, so using the new operator gets rid of that warning, just make sure to call the base class Dispose from the child class (and implement it the right way).

The dispose for the child would become something like:

public class DisposableChild : DisposableParent, IDisposable
{
    private bool _disposed = false;

    public new void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (!_disposed)
            {
                base.Dispose();
                Console.WriteLine("The child was disposed.");
                _disposed = true;
            }
        }
    }
}

And yes, this still works if you do something like:

using (DisposableParent p = new DisposableChild())
{

}

But something like this can break it:

public class Program
{
    public static void Main()
    {
        DisposableChild c = new DisposableChild();
        DisposeOfIt(c);

        Console.ReadKey(true);
    }

    public static void DisposeOfIt(DisposableParent p)
    {
        p.Dispose();
    }
}

Only prints out that the parent was disposed. So if you used this method you would have to be careful about controlling the lifetime of your objects.

like image 57
Ron Beyer Avatar answered Oct 01 '22 17:10

Ron Beyer