0

Im aware of the dispose pattern and would like to properly dispose my Socket resource. In the documentation they recommend to use SafeHandles, but I'm not sure how exactly this works with System.Net.Socket. I discovered that the Socket class itself includes a SafeSocketHandle, but I have no idea how to use it. Do I need to dispose the handle and the socket or is it sufficient to dispose only the handle? And I assume in the class I'm only using the handle for socket operations, right?

public class MySocket : IDisposable
{
    private SafeSocketHandle _handle;
    private bool _disposed = false;

    public MySocket(AddressFamily addressFamily)
    {
        Socket s = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
        _handle = s.SafeHandle;
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            _handle.Dispose();
        }

        _disposed = true;
    }
}

And maybe someone is also able to explain why SafeHandles should be used? I mean wouldn't this be sufficient?:

public class MySocket : IDisposable
{
    private Socket _socket;
    private bool _disposed = false;

    public MySocket(AddressFamily addressFamily)
    {
        _socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            _socket.Dispose();
        }

        _disposed = true;
    }
}
Josh
  • 287
  • 1
  • 8
  • Note that you've missed the finalizers off your code sample -- they're important. – canton7 Nov 14 '19 at 11:11
  • @canton7 Is not the hole point of the pattern to avoid working with the finalizer directly? Also in this example they don't implement the finalizer: https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#using-a-safe-handle-to-implement-the-dispose-pattern-for-a-base-class – Josh Nov 14 '19 at 11:17
  • The point of `SafeHandle` is to avoid users shooting themselves in the foot when they try and release unmanaged resources. It's true that if you're using a `SafeHandle`, you don't need to implement the full dispose pattern, see my answer. But if you *are* implementing the full dispose pattern, you need to do it properly. In your code, `GC.SuppressFinalize(this)` does nothing (since you don't have a finalizer), and nothing ever calls your `void Dispose(bool disposing)` method with `false`. – canton7 Nov 14 '19 at 11:18

1 Answers1

1

You should use a SafeHandle when you are directly managing an unmanaged resource.

With Socket, there is an underlying unmanaged resource, but that's handled by the Socket class. There's no need for you to get involved in it -- Socket itself is a managed resource, not an unmanaged resource. Socket has its own finalizer, which will (may) release the underlying unmanaged resource if you forget to dispose it.

So, here you don't need to worry about SafeHandles. Just implement IDisposable and call _socket.Dispose().


You don't need to implement the full Dispose pattern here, unless you might have a derived class which owns its own unmanaged resources. It's sufficient to write:

public class MySocket : IDisposable
{
    private Socket _socket;
    private bool _disposed = false;

    public MySocket(AddressFamily addressFamily)
    {
        _socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
    }

    public void Dispose()
    {
        _socket.Dispose();
        _disposed = true;
    }
}

Indeed, many coding standards mandate that unmanaged resources must be wrapped in a SafeHandle. If you do this, there's no need to ever implement the full Dispose pattern.

If you do need to implement the full dispose pattern, you also need to write a finalizer. The code in your question doesn't do this.

In fact, the dispose pattern encourages users down quite a dangerous path -- writing correct code in your void Dispose(bool disposing) method is really quite hard, and there are pitfalls which most users aren't aware of. This is why SafeHandle was introduced in .NET 2.0 -- the runtime has special support for it which avoids those pitfalls -- but the advice around IDisposable seems to have never been updated.

canton7
  • 37,633
  • 3
  • 64
  • 77
  • Now it's clearer to me. Thanks! So basically I could use the SafeHandle to avoid implementing the finalizer. But because Socket takes care of the unmanaged resources I don't need a SafeHandle. Therefore the simple disposing is sufficient. But could you do me a favour and explain me very simple what the unmanaged resources in this case are and how Socket takes care of them? This would help me in future to decide if I need a SafeHandle – Josh Nov 14 '19 at 11:45
  • 1
    Not that `SafeHandle` does more than just letting you avoid writing a finalizer: it avoids some pitfalls around releasing unmanaged resources. For example, did you know that your class can be finalized *while one of its methods is executing*? That means that you can close a handle while a native function is using it, which is very bad. `Socket` is a particularly complicated example -- `FileStream` is a lot easier. [Read the source](https://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,e23a38af5d11ddd3), look at how `_handle` is used. – canton7 Nov 14 '19 at 12:06