title: Elegantly handle task cancellation
body: <p>When using tasks for large/long running workloads that I need to be able to cancel I often use a template similar to this for the action the task executes:</p>
  <pre><code>public void DoWork(CancellationToken cancelToken)
  {
      try
      {
          //do work
          cancelToken.ThrowIfCancellationRequested();
          //more work
      }
      catch (OperationCanceledException)
      {
          throw;
      }
      catch (Exception ex)
      {
          Log.Exception(ex);
          throw;
      }
  }
  </code></pre>
  <p>The <code>OperationCanceledException</code> should not be logged as an error but must not be swallowed if the task is to transition into the cancelled state.  Any other exceptions do not need to be dealt with beyond the scope of this method.</p>
  <p>This always felt a bit clunky, and visual studio by default will break on the throw for <code>OperationCanceledException</code> (though I have 'break on User-unhandled' turned off now for <code>OperationCanceledException</code> because of my use of this pattern).</p>
  <p>UPDATE: It's 2021 and C#9 gives me the syntax I always wanted:</p>
  <pre class="lang-cs prettyprint-override"><code>public void DoWork(CancellationToken cancelToken)
  {
      try
      {
          //do work
          cancelToken.ThrowIfCancellationRequested();
          //more work
      }
      catch (Exception ex) when (ex is not OperationCanceledException)
      {
          Log.Exception(ex);
          throw;
      }
  }
  </code></pre>
  <strike>
  Ideally I think I'd like to be able to do something like this:
  <pre><code>public void DoWork(CancellationToken cancelToken)
  {
      try
      {
          //do work
          cancelToken.ThrowIfCancellationRequested();
          //more work
      }
      catch (Exception ex) exclude (OperationCanceledException)
      {
          Log.Exception(ex);
          throw;
      }
  }
  </code></pre>
  </strike>
  i.e. have some sort of exclusion list applied to the catch but without language support that is not currently possible (@eric-lippert: c# vNext feature :)).
  <p>Another way would be through a continuation:</p>
  <pre><code>public void StartWork()
  {
      Task.Factory.StartNew(() =&gt; DoWork(cancellationSource.Token), cancellationSource.Token)
          .ContinueWith(t =&gt; Log.Exception(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
  }
  
  public void DoWork(CancellationToken cancelToken)
  {
      //do work
      cancelToken.ThrowIfCancellationRequested();
      //more work
  }
  </code></pre>
  <p>but I don't really like that as the exception technically could have more than a single inner exception and you don't have as much context while logging the exception as you would in the first example (if I was doing more than just logging it).</p>
  <p>I understand this is a bit of a question of style, but wondering if anyone has any better suggestions?</p>
  <p>Do I just have to stick with example 1?</p>