任务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;
}