Question #1:
StartAsync
handles the disposal of _clientWebSocket
and _tokenSource
. So do I really need to dispose these in Dispose()
as well? I think I should keep _semaphore.Dispose()
only in the Dispose()
, because my code already handles the rest.
Question #2:
What if the user forgets to call Dispose()
or wrap it in using
? It's usually solved by calling Dispose()
in the deconstructor/finalizer but in this case my class is sealed
.
public sealed class Client : IDisposable
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
private ClientWebSocket? _clientWebSocket;
private CancellationTokenSource? _tokenSource;
public void Dispose()
{
_semaphore.Dispose();
// TODO: Do I need to dispose these since my code below does that?
_clientWebSocket?.Dispose();
_clientWebSocket = null;
_tokenSource?.Cancel();
_tokenSource = null;
}
public Task StartAsync()
{
_clientWebSocket = new ClientWebSocket();
_tokenSource = new CancellationTokenSource();
try
{
...
}
catch (Exception ex)
{
}
finally
{
_clientWebSocket?.Dispose();
_clientWebSocket = null;
_tokenSource?.Cancel();
_tokenSource = null;
}
}
public ValueTask SendAsync()
{
if (_clientWebSocket is { State: WebSocketState.Open })
{
return;
}
...
}
}