Как IDisposable и IAsyncDisposable работают вместе?
Класс ниже не
sealed
, что означает, что он считается наследственным. Я взял реализацию IDisposable/IAsyncDisposable отсюда и пытаюсь понять, почему
.Dispose
вызовы дублируются как в Dispose, так и в DisposeAsync. Сможет ли кто-нибудь объяснить мне, как это работает более глубоко / или я бы сказал, на низком уровне, чтобы я действительно знал, как его использовать в будущем?
public class Client : IDisposable, IAsyncDisposable
{
private readonly ILogger<Client> _logger;
private readonly Channel<string> _outputChannel;
private ClientWebSocket? _clientWebSocket;
private CancellationTokenSource? _cancellationSource;
private Task _receiving = Task.CompletedTask;
private Task _sending = Task.CompletedTask;
public Client(ILoggerFactory? loggerFactory = default)
{
_logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<Client>();
}
public bool IsDisposed { get; protected set; }
...
/// <summary>
/// Checks if this object has been disposed.
/// </summary>
/// <exception cref="ObjectDisposedException">Thrown if the object has been disposed.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void DoDisposeChecks()
{
if (IsDisposed)
{
throw new ObjectDisposedException(nameof(Client));
}
}
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
/// <param name="disposeManaged">A value indicating whether or not to dispose of managed resources.</param>
protected virtual void Dispose(bool disposeManaged)
{
if (IsDisposed)
{
return;
}
if (disposeManaged)
{
_logger.LogDebug("Socket {Id} is disposing", Id);
_clientWebSocket?.Dispose();
_cancellationSource?.Dispose();
_outputChannel.Writer.TryComplete();
_logger.LogDebug("Socket {Id} disposed", Id);
}
IsDisposed = true;
}
/// <summary>
/// Asynchronously disposes of managed resources.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
protected virtual ValueTask DisposeAsyncCore()
{
if (IsDisposed)
{
return default;
}
_logger.LogDebug("Socket {Id} is disposing", Id);
_clientWebSocket?.Dispose();
_cancellationSource?.Dispose();
_outputChannel.Writer.TryComplete();
_logger.LogDebug("Socket {Id} disposed", Id);
IsDisposed = true;
return default;
}
/// <inheritdoc />
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}