Самостоятельная отмена задачи с OperationCanceledException

Я заметил, что задача может отменить себя, выдав OperationCanceledException. Обычно можно указать удобную для пользователя причину в OperationCanceledExceptionконструктор, который позже становится сообщением об исключении. Однако в сценарии задачи это не выглядит так. Исключение отменяет задачу, но в конечном итоге преобразуется в TaskCanceledException, а исходное сообщение заменяется общим.

Есть ли аккуратный способ указать причину отмены в этом примере? Я посмотрел на CancellationTokenSource, но тоже не увидел варианта.

  class Program
  {
    static async Task MyAsyncMethod()
    {
      await Task.Delay(TimeSpan.FromSeconds(1));
      throw new OperationCanceledException("My lost cancellation reason");
    }


    static void Main(string[] args)
    {
      var task = MyAsyncMethod();
      try
      {
        task.Wait();
      }
      catch (AggregateException ecxeptions)
      {
        var exception = ecxeptions.InnerException;
        Console.WriteLine(exception.GetType());       //TaskCanceledException
        Console.WriteLine(exception.Message);         //A task was canceled.
        Console.WriteLine(task.Status);               //Canceled
        Console.WriteLine(task.Exception == null);    //true
      }

      Console.Read();
    }
  }

person nan    schedule 04.11.2015    source источник


Ответы (1)


Это происходит только тогда, когда вы используете Task.Wait, который создает новый AggregateException, который объединяет все внутренние исключения.

Если вы используете await, фактическое исключение будет выдано и будет иметь правильное сообщение. Поскольку вы не можете использовать await в Main, вы можете использовать GetAwaiter().GetResult(), который будет блокироваться синхронно, но все равно будет создавать то же исключение, что и await (без агрегации):

static async Task MyAsyncMethod()
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    throw new TaskCanceledException("My lost cancellation reason");
}

static void Main()
{
    var task = MyAsyncMethod();
    try
    {
        task.GetAwaiter().GetResult();
    }
    catch (TaskCanceledException exception)
    {
        Console.WriteLine(exception.GetType()); // TaskCanceledException
        Console.WriteLine(exception.Message); // My lost cancellation reason
        Console.WriteLine(task.Status); // Canceled
        Console.WriteLine(task.Exception == null); // true
    }

    Console.Read();
}
person i3arnon    schedule 04.11.2015