我在任务中有一个无限循环。在某些情况下,此任务会抛出异常并终止。请考虑以下代码段。
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
int x = await FirstTask();
window.Title = "FirstTask completed with " + x.ToString();
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}
public async Task<int> FirstTask()
{
Task<int> secondTask;
int result;
secondTask = SecondTask();
textbox.Text = "Awaiting SecondTask result";
result = await secondTask;
textbox.Text = result;
secondTask.ContinueWith(async (Task t) =>
{
var thirdTask = ThirdTask();
thirdTask.ContinueWith(
async (m) =>
await Task.Run(() =>
{
throw thirdTask.Exception.InnerException;
}),
TaskContinuationOptions.OnlyOnFaulted);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
return 5;
}
public async Task<int> SecondTask()
{
await Task.Delay(1500);
return 8;
}
public async Task ThirdTask()
{
while (true)
{
await Task.Delay(500);
throw new ArgumentException("thirdException");
}
}
我的问题在于无法将从ThirdTask抛出的异常传播到Button_Click事件。显然,等待它不是一个选项,因为它是一个持续的无限操作(这只是简化为快速失败)。但是,如果仅在ThirdTask失败时触发,则等待重新抛出异常的“短”任务没有问题。请注意,我对ThirdTask的操作不感兴趣,除非它失败,也就是我能够在事件处理程序中等待FirstTask。
试验表明,即使是最简单的示例也不会从ContinueWith块传播异常。
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Task task = Task.Run(async () => { await Task.Delay(1000); });
task.ContinueWith( (t) => { throw new ArgumentException("test"); }, TaskContinuationOptions.OnlyOnRanToCompletion);
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}
那么,我如何将一个异常从ContinueWith传播到调用上下文,因为抛出它的任务有一个无限循环,这阻止我等待它?
我想解决的问题有两个: 首先,我需要初始化一个资源(FirstTask),为了做到这一点,我首先需要获取它(SecondTask)然后用它开始一个进程(ThirdTask),最后,资源的初始化(FirstTask)返回指示资源状态的值,它不依赖于进程(ThirdTask)。进程(ThirdTask)重复调用另一个任务(在本例中为Task.Delay)并对其执行一些工作,但它可能会失败。在这种情况下,它会抛出一个需要处理的异常。
第二部分是第二个代码示例的一般情况,关于如何从ContinueWith抛出异常以由调用上下文处理。
答案 0 :(得分:1)
鉴于抛出它的任务有一个无限循环,这阻止我等待它?
这绝不会阻止你等待它。处理它抛出异常的情况的[最简单]方法特别是await
它。
您可以简单地实现此方法:
public async Task FirstTask()
{
Task<int> secondTask = SecondTask();
textbox.Text = "Awaiting SecondTask result";
textbox.Text = await secondTask;
await ThirdTask();
}
如果click处理程序需要同时使用第二个操作的结果更新texbox并在第三个操作失败时更新UI,那么您需要不在FirstTask
中包装这两个操作并直接从点击处理程序:
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
textbox.Text = "Awaiting SecondTask result";
int x = await SecondTask();
window.Title = "SecondTask completed with " + x.ToString();
await ThirdTask();
}
catch (ArgumentException ex)
{
textbox.Text = ex.Message;
}
}