IDisposable cascade

Viewed 274

I have a class to model an external device via TCP/IP. This class creates a client, which is basically a wrapper for System.Net.Sockets.TcpClient and instances of this class are held by an application class.

according to https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#cascade-dispose-calls if a class owns a field that implements IDisposable it should also implement IDisposable.

So in my situation, TcpClient implements IDisposable, therefore my client class has to implement IDisposable, therefore my external device class has to implement IDisposable, therefore my application class has to implement IDisposable.

Sounds cumbersome, so I´m questioning if thats the right way to do it?

public class Client : IDisposable
{
    private TcpClient _tcpClient;
    ...

    public void Connect()
    {
        _tcpClient = new TcpClient();
        if (!_tcpClient.ConnectAsync(address, port).Wait(1000))
        ...
    }

    public void Disconnect()
    {
        _tcpClient?.Dispose();
        _tcpClient = null;
    }

    #region IDisposable
    ...
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        if (disposing)
        {
            _tcpClient?.Dispose();
            _tcpClient = null;
        }
        _disposed = true;
    }
    #endregion

    ...
}


public class SM15k : IDisposable
{
    private readonly Client _client;
    ...

    public SM15k()
    {
        _client = new Client();
    }

    #region IDisposable
    ...
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        if (disposing)
        {
            _client.Dispose();
        }
        _disposed = true;
    }
    #endregion
    ...
}


public class App : IDisposable
{
    private SM15k _SM15k;

    #region IDisposable
    ...
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        if (disposing)
        {
            _SM15k?.Dispose();
            _SM15k = null;
        }
        _disposed = true;
    }
    #endregion
    ...
}
1 Answers

Yes that is the correct way to do it.

Since you have dependencies that needs to be disposed you'll have to make sure that they are disposed all the way down. Otherwise, when you dispose your "external device class" the TcpClient at the bottom won't be properly disposed and you might get a resource leak (ports remaining open for example).

Related