ContinueWith 和 WhenAll 如何处理异常?
How to handle exceptions with ContinueWith and WhenAll?
我正在尝试异步加载多个文件并在每个文件加载完成后通知 UI,
_loadCancellationTokenSource = new CancellationTokenSource();
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
var files = await picker.PickMultipleFilesAsync();
LoadedFiles.Clear();
loads = await Task.WhenAll(files.Select(file =>
{
var load = LoadAsync(file);
load.ContinueWith(t =>
{
if (t.IsCompleted) LoadedFiles.Add(file.Path);
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
}, scheduler);
return load;
}));
private Task<Foo> LoadAsync(StorageFile file)
{
// exception may be thrown inside load
return Load(file, _loadCancellationTokenSource.Token);
}
问题是抛出异常时,没有处理。我知道为什么,因为 ContinueWith
创建了一个新任务,但我 return 正在执行旧任务。
这是因为ContinueWith
是一个无效的任务。但我不知道如何正确 return 结果。我不确定使用 t.Result
是否安全,因为它可能会阻塞 UI 线程?
PS,我试过这段代码,但我得到 a task was cancelled exception
并且应用程序崩溃,即使我没有取消任何任务。加载某些文件时只会抛出一些异常。
load = (await Task.WhenAll(files.Select(file =>
{
var load = LoadAsync(file);
load.ContinueWith(t =>
{
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
}, _loadCancellationTokenSource.Token, TaskContinuationOptions.NotOnRanToCompletion, scheduler);
return load.ContinueWith(t =>
{
LoadedFiles.Add(file.Path);
return (file, t.Result);
}, _loadCancellationTokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler); ;
})));
感谢@Jimi,我能够通过查看任务状态来解决这个问题。
loads = (await Task.WhenAll(files.Select(file =>
{
return LoadAsync(file).ContinueWith(t =>
{
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
if (t.Status == TaskStatus.RanToCompletion)
{
LoadedFiles.Add(file.Path);
return t.Result;
}
return null;
}, scheduler);
}))).Where(x => x != null).ToArray();
我正在尝试异步加载多个文件并在每个文件加载完成后通知 UI,
_loadCancellationTokenSource = new CancellationTokenSource();
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
var files = await picker.PickMultipleFilesAsync();
LoadedFiles.Clear();
loads = await Task.WhenAll(files.Select(file =>
{
var load = LoadAsync(file);
load.ContinueWith(t =>
{
if (t.IsCompleted) LoadedFiles.Add(file.Path);
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
}, scheduler);
return load;
}));
private Task<Foo> LoadAsync(StorageFile file)
{
// exception may be thrown inside load
return Load(file, _loadCancellationTokenSource.Token);
}
问题是抛出异常时,没有处理。我知道为什么,因为 ContinueWith
创建了一个新任务,但我 return 正在执行旧任务。
这是因为ContinueWith
是一个无效的任务。但我不知道如何正确 return 结果。我不确定使用 t.Result
是否安全,因为它可能会阻塞 UI 线程?
PS,我试过这段代码,但我得到 a task was cancelled exception
并且应用程序崩溃,即使我没有取消任何任务。加载某些文件时只会抛出一些异常。
load = (await Task.WhenAll(files.Select(file =>
{
var load = LoadAsync(file);
load.ContinueWith(t =>
{
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
}, _loadCancellationTokenSource.Token, TaskContinuationOptions.NotOnRanToCompletion, scheduler);
return load.ContinueWith(t =>
{
LoadedFiles.Add(file.Path);
return (file, t.Result);
}, _loadCancellationTokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler); ;
})));
感谢@Jimi,我能够通过查看任务状态来解决这个问题。
loads = (await Task.WhenAll(files.Select(file =>
{
return LoadAsync(file).ContinueWith(t =>
{
if (t.IsFaulted) NotifyUser(t.Exception.Message, NotifyType.ErrorMessage);
if (t.IsCanceled) NotifyUser("operation was canceled.", NotifyType.ErrorMessage);
if (t.Status == TaskStatus.RanToCompletion)
{
LoadedFiles.Add(file.Path);
return t.Result;
}
return null;
}, scheduler);
}))).Where(x => x != null).ToArray();