如何使用ContinueWith和WhenAll处理异常?

时间:2019-01-01 05:39:55

标签: c# asynchronous exception-handling task

我正在尝试异步加载多个文件,并在每次加载完文件时通知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创建了一个新任务,但我又返回了旧任务。

这是因为ContinueWith是无效任务。但我不知道如何正确返回结果。我不确定使用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); ;
})));

1 个答案:

答案 0 :(得分:0)

感谢@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();