Как обрабатывать исключения с помощью ContinueWith и WhenAll? - PullRequest
0 голосов
/ 01 января 2019

Я пытаюсь загрузить несколько файлов асинхронно и сообщать пользовательскому интерфейсу, когда загружается каждый файл,

_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, потому что это может заблокировать поток пользовательского интерфейса?


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 голосов
/ 01 января 2019

Благодаря @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();
...