任务1:

public Task SendMail(string email)
 {
  ...
 }


任务2:

public Task<int> SaveToDB(User user)
 {
  ...
 }


我需要做什么:


当task1失败时,应返回“发送失败”信息;
当task1成功时,task2开始。
当task2失败时,应返回“保存失败”信息。
当task2成功时,应返回“保存成功”信息。


请帮助我找到解决方案:

public Task<string> SendAndSave(User user){
var task1 = SendMail(user.Email);
var task1Failed = task1.ContinueWith(t =>
{
     var e = task1.Exception;
     return "Send Failed";
},
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);

var task2 = task1.ContinueWith(t =>
{
    var save = SaveToDB(user);
    try
    {
        int result = save.Result;
        return "Save Succeeded";
      }
     catch(AggregateException ae)
     {
          return "Save Failed";
      }
      },
      TaskContinuationOptions.NotOnFaulted);

 return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);
 }


当我运行它时,我收到一个错误。

我将其调用为:

var result = SendAndSave(user).Result;

错误发生在:

public Task<string> SendAndSave(User user)
{
      ...
      return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result);   //Here: A task was cancelled
 }


调试之后,我有两个问题:


问题1:在创建task1,task1Failed,task2之后,每个的值
CreationOption属性为“ none”,尽管其状态为
“ WaitingForActivation”。似乎所有继续选项都是
无效。
Q2:对于Task.Factory.ContinueWhenAny(new [] {task1Failed,
task2},t => t.Result),我们将其命名为“ factoryTask”,
当任何人似乎无效时继续。在内部设置断点后
每个task1Failed,task2和factoryTask的情况,我偶尔都能看到
尽管首先打了factoryTask的断点
在task1Failed或task2完成后应点击。


有人可以帮忙吗?谢谢。

最佳答案

尽管我不完全理解您的问题,但是我理解这里的问题,基本上,您将始终拥有task1Failed或task2完成,但不是全部都完成,而另一个将被取消!
因此,在WaitOnAny调用中,如果发现其中一个任务已被取消,则会崩溃,而这实际上取决于task参数的顺序,因此在上面的示例中,您首先传递task1failed,因此,如果此任务完成,ContinueWhenAny将起作用很好,因为它检查的第一个任务已经完成,因此不会检查其他任务,但是如果task1Failed没有运行,因此它处于取消状态,ContinueWhenAny会抛出!

为避免这种情况,您需要改用TaskCompletetionSource,然后运行的任务将设置该值,然后最后返回tcs.Task.Result。

public Task<string> SendAndSave(User user){
var tcs = new TaskCompletionSource<string>();
var task1 = SendMail(user.Email);
var task1Failed = task1.ContinueWith(t =>
{
     var e = task1.Exception;
     tcs.TrySetResult("Send Failed");
},
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);

var task2 = task1.ContinueWith(t =>
{
    var save = SaveToDB(user);
    try
    {
        int result = save.Result;
        tcs.TrySetResult("Save Succeeded");
    }
    catch(AggregateException ae)
    {
       tcs.TrySetResult("Save Failed");
    }
},TaskContinuationOptions.NotOnFaulted);

 return tcs.Task.Result;
}

08-15 22:26