Подтвердить что ты не робот

Лучший способ показать сообщения об ошибках в асинхронных методах

Тот факт, что мы не можем использовать ключевое слово await в блоках catch, делает довольно неудобным отображение сообщений об ошибках из методов async в WinRT, так как API MessageDialog является асинхронным. В идеале я хотел бы написать это:

    private async Task DoSomethingAsync()
    {
        try
        {
            // Some code that can throw an exception
            ...
        }
        catch (Exception ex)
        {
            var dialog = new MessageDialog("Something went wrong!");
            await dialog.ShowAsync();
        }
    }

Но вместо этого я должен написать это следующим образом:

    private async Task DoSomethingAsync()
    {
        bool error = false;
        try
        {
            // Some code that can throw an exception
            ...
        }
        catch (Exception ex)
        {
            error = true;
        }

        if (error)
        {
            var dialog = new MessageDialog("Something went wrong!");
            await dialog.ShowAsync();
        }
    }

Все методы, необходимые для этого, должны следовать аналогичному шаблону, который мне действительно не нравится, потому что он уменьшает читаемость кода.

Есть ли лучший способ справиться с этим?


EDIT: Я придумал это (что похоже на то, что подсказывает в комментариях):

static class Async
{
    public static async Task Try(Func<Task> asyncAction)
    {
        await asyncAction();
    }

    public static async Task Catch<TException>(this Task task, Func<TException, Task> handleExceptionAsync, bool rethrow = false)
        where TException : Exception
    {
        TException exception = null;
        try
        {           
            await task;
        }
        catch (TException ex)
        {
            exception = ex;
        }

        if (exception != null)
        {
            await handleExceptionAsync(exception);
            if (rethrow)
                ExceptionDispatchInfo.Capture(exception).Throw();
        }
    }
}

Использование:

private async Task DoSomethingAsync()
{
    await Async.Try(async () => 
    {
        // Some code that can throw an exception
        ...
    })
    .Catch<Exception>(async ex =>
    {
        var dialog = new MessageDialog("Something went wrong!");
        await dialog.ShowAsync();
    });
}

.Catch<...> вызовы могут быть закодированы, чтобы имитировать несколько блоков catch.

Но я не очень доволен этим решением; синтаксис еще более неудобен, чем раньше...

4b9b3361

Ответ 1

Теперь С# 6 поддерживает await в catch и finally, поэтому код можно записать так, как я этого хотел; обходной путь больше не нужен.

Ответ 2

у вас уже есть эта функциональность в TPL

        await Task.Run(async () =>
        {
            // Some code that can throw an exception
            ...
        }).ContinueWith(async (a) =>
        {
            if (a.IsFaulted)
            {
                var dialog = new MessageDialog("Something went wrong!\nError: "
                           + a.Exception.Message);
                await dialog.ShowAsync();
            }
            else
            {
                var dialog2 = new MessageDialog("Everything is OK: " + a.Result);
                await dialog2.ShowAsync();
            }
        }).Unwrap();

В этой машине у меня нет Windows 8, поэтому я тестировал в Windows 7, но я думаю, что это то же самое. *Редактировать как указано в комментариях, необходимых .Unwrap(); в конце для ожидания работы