在异步方法中显示错误消息的更好方法



由于MessageDialog API是异步的,因此我们不能在catch块中使用await关键字,这使得在WinRT中显示来自异步方法的错误消息非常困难。理想情况下,我希望能够写下:

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

所有需要这样做的方法都必须遵循类似的模式,我真的不喜欢,因为这会降低代码的可读性。

有更好的方法来处理这个问题吗?


编辑:我想出了这个(类似于svick在评论中建议的):

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

CCD_ 4调用可以被链接以模仿多个CCD_。

但我对这个解决方案并不满意;语法比以前更尴尬了。。。

您已经在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();最后等待工作

C#6现在在catchfinally中支持await,因此代码可以按照我想要的方式编写;不再需要变通方法。