抛出异常时任务不处于故障状态

时间:2017-12-08 23:03:02

标签: c# .net task-parallel-library

在以下示例中抛出异常时,我似乎无法弄清楚为什么我的任务不处于故障状态(假设engine.Send(...)抛出异常):

       var receiverTask = new Task<Task>(async () => {
            result = await Task.FromResult(engine.Send(someObject));
        });
        receiverTask.Start();
        receiverTask.Wait();

如果我在receiverTask.IsFaulted之后receiverTask.Wait()返回false,而不是我想象的那样。

我一直在读,我需要使用类似下面的结构:

receiverTask.ContinueWith(t => { /* error handling */ },
    TaskContinuationOptions.OnlyOnFaulted);

但我似乎无法弄清楚如何将其整合到示例代码中。我是否在Start()之前调用它?在Wait()之前?

我希望调用程序能够以某种方式意识到receiverTask已抛出异常并失败。有什么指针吗?

1 个答案:

答案 0 :(得分:2)

如果我正确理解了这种情况,您可以省略.Start()并稍微使用.Wait()

(我不知道你的engine.Send(someObject)方法是什么,所以我必须假设。)

让我们说你的方法返回一个bool(它没关系,但只是写下来。

如果是同步的,则返回的任务可以是:

 Task<bool> receiverTask = Task<bool>.Run(async () =>
            await Task<bool>.FromResult(engine.Send(someObject)));

 Task<bool> receiverTask = Task.Factory.StartNew(async delegate
 {
    bool _result = await Task<bool>.FromResult(engine.Send(someObject));
    return _result;
 }, TaskScheduler.Default).Unwrap();

如果它是异步的,则返回的Task可以是:

 Task<bool> receiverTask = Task.Run(async () =>
            await engine.Send(someObject));

 Task<bool> receiverTask = Task.Factory.StartNew(async delegate
 {
    bool _result = await engine.Send(someObject);
    return _result;
 }, TaskScheduler.Current).Unwrap<bool>();


(但是,如果没有其他异步/等待声明,所有这些都会阻塞。)

安排完任务后,可以定义一些延续条件来评估其状态 如果任务处于某种错误状态(已取消,已中止等),则其.IsCompleted属性报告true,但.Status属性不是TaskStatus.RanToCompletion

 receiverTask.ContinueWith(t =>
 {
    //Continue on faulted
    Console.WriteLine(receiverTask.GetAwaiter().IsCompleted);
    if (receiverTask.IsFaulted)
       Console.WriteLine(receiverTask.Exception.InnerExceptions[0].Message);
 }, TaskContinuationOptions.OnlyOnFaulted).Wait(0);

 receiverTask.ContinueWith(t =>
 {
    //Continue on canceled
    Console.WriteLine(receiverTask.GetAwaiter().IsCompleted);
    if (receiverTask.IsCanceled)
       Console.WriteLine(receiverTask.Exception.InnerExceptions[0].Message);
 }, TaskContinuationOptions.OnlyOnCanceled).Wait(0);

 receiverTask.ContinueWith(t =>
 {
    //Standard behaviour
    Console.WriteLine(receiverTask.GetAwaiter().IsCompleted);
    Console.WriteLine(receiverTask.Status.ToString());
 }, TaskContinuationOptions.None).Wait();

 //This writes only if no errors have been raised
 if (receiverTask.Status == TaskStatus.RanToCompletion)
    Console.WriteLine("Completed: {0}  Result: {1}", receiverTask.GetAwaiter().IsCompleted, receiverTask.Result);


但您也可以使用Try / Catch块:

 try
 {
    receiverTask.Wait();

    if (receiverTask.Status == TaskStatus.RanToCompletion)
       Console.WriteLine("Completed: {0}  Result: {1}", receiverTask.GetAwaiter().IsCompleted, receiverTask.Result);
 }
 catch (Exception)
 {
    receiverTask.ContinueWith(t =>
    {
       //With continuation
       if (receiverTask.IsFaulted)
          Console.WriteLine(receiverTask.Exception.InnerExceptions[0].Message);
    }, TaskContinuationOptions.OnlyOnFaulted);

       //or without
       //if (receiverTask.IsCanceled)
       //Console.WriteLine(receiverTask.Exception.InnerExceptions[0].Message);
 }