Search code examples
c#async-awaitcancellationtokensource

Take a cancellationtoken or expose a method for cancellation?


Which one of the following two examples is preferred?

Example 1

public class Worker : IDisposable
{
    private CancellationTokenSource tokenSource;

    public string State { get; private set; }

    public async Task StartWorkAsync()
    {
        tokenSource = new CancellationTokenSource();

        this.State = "Working";
        await Task.Delay(5000, tokenSource.Token);
    }

    public void StopWork()
    {
        this.tokenSource.Cancel();
        this.State = "Stopped";
    }

    public void Dispose()
    {
        tokenSource?.Dispose();
    }
}

Example 2

public class Worker
{
    public string State { get; private set; }

    public async Task StartWorkAsync(CancellationToken ctoken)
    {
        ctoken.ThrowIfCancellationRequested();

        this.State = "Working";
        try
        {
            await Task.Delay(5000, ctoken);
        }
        catch (AggregateException) when (ctoken.IsCancellationRequested)
        {
            this.State = "Stopped";
        }
    }
}

Or perhaps just both? However, I assume that it's expect that it's common practice to take a cancellationtoken with an async method.


Solution

  • You should accept a CancellationToken as an argument and allow the OperationCanceledException to propagate:

    public async Task StartWorkAsync(CancellationToken ctoken)
    {
      ctoken.ThrowIfCancellationRequested();
    
      this.State = "Working";
      try
      {
        await Task.Delay(5000, ctoken);
      }
      catch (OperationCanceledException)
      {
        this.State = "Stopped";
        throw;
      }
    }