Search code examples
c#socketsdisposefinalizer

C# proper use of Dispose with SafeSocketHandle


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;
    }
}

Solution

  • 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.