任务1:
public Task SendMail(string email)
{
...
}
TASK2:
public Task<int> SaveToDB(User user)
{
...
}
我需要做什么:
请帮我找一个解决方案:
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
}
调试后,我有两个问题:
Q1:在task1之后,task1Failed,task2被创建,每个值都是 CreationOption属性为“none”,尽管其状态为 “WaitingForActivation”。似乎所有的延续选择都是 无效。
Q2:对于Task.Factory.ContinueWhenAny的任务(new [] {task1Failed, task2},t =&gt; t.Result),让我们把它命名为“factoryTask”,即 ContinueWhenAny似乎无效。在内部放了一个断点 每个task1Failed,task2和factoryTask,我偶尔可以看到 尽管如此,工厂中的断点首先被击中了 应该在task1Failed或task2完成后进行命中。
有人可以帮忙吗?感谢。
答案 0 :(得分:1)
虽然我不完全理解你的问题,但我理解这里的问题,基本上你总是有task1Failed或task2完成但不是两者都有,而另一个将被取消! 所以在WaitOnAny调用中,如果它发现其中一个任务已被取消,它将崩溃,这实际上取决于tasks参数的顺序,所以在上面的例子中你首先传递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;
}