Better way to show error messages in async methods

岁酱吖の 提交于 2019-12-12 08:23:42

问题


The fact that we can't use the await keyword in catch blocks makes it quite awkward to show error messages from async methods in WinRT, since the MessageDialog API is asynchronous. Ideally I would like be able to write this:

    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();
        }
    }

But instead I have to write it like this:

    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();
        }
    }

All methods that need to do this have to follow a similar pattern, which I really don't like, because it reduces the code readability.

Is there a better way to handle this?


EDIT: I came up with this (which is similar to what svick suggested in his comments):

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();
        }
    }
}

Usage:

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<...> calls can be chained to mimick multiple catch blocks.

But I'm not really happy with this solution; the syntax is even more awkward than before...


回答1:


you already have that functionality in 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();

In this machine I don't have Windows 8 so I tested in Windows 7 but I think is the same. *Edit as stated in the comments its needed .Unwrap(); in the end for the await to work




回答2:


C# 6 now supports await in catch and finally, so the code can be written the way I wanted it; a workaround is no longer needed.



来源:https://stackoverflow.com/questions/18310236/better-way-to-show-error-messages-in-async-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!