4

由于捕获的异常,显示消息对话框的正确方法是什么?

我最初尝试过

try
{
    await DoSomething();
}
catch(InvalidOperation ex)
{
    await MessageDialog(ex.Message).ShowAsync();
}
catch(CommunicationException)
{
    await MessageDialog(StringResourceLoader.LoginError).ShowAsync();
}

这不起作用,因为您不能await在 try 块内。取出 await 命令会使编译器显示以下警告:

由于不等待此调用,因此在调用完成之前继续执行当前方法。考虑将“等待”运算符应用于调用结果

我不喜欢在我的代码中保留这些警告,因为在某些地方人们忘记了使用await,因此很难找到错误。

更改消息对话框语句以var task = new MessageDialog(ex.Message).ShowAsync().AsTask();消除所有警告和错误,但我不确定这是解决它的好方法(技术上很糟糕,原因与它希望我await打电话的原因相同)

最后,我尝试在 catch 之外存储异常并执行我的逻辑来向用户显示什么(包括确定抛出什么类型的异常的所有逻辑),通过:

Exception thrownException = null;
try
{
    await DoSomething();
}
catch(Exception ex)
{
    thrownException = ex;
}

if (thrownException is InvalidOperationException)
    await MessageDialog(ex.Message).ShowAsync();
else if (thrownException is CommunicationException)
    await MessageDialog(StringResourceLoader.LoginError).ShowAsync();

我不确定我是否觉得这是最好的方法。有什么想法应该怎么做?

4

1 回答 1

4

编辑: 在汉斯对其他问题发表评论后,我最终通过创建以下类来解决它:

public static class MessageDialogDisplayer
{
    private static readonly ConcurrentQueue<MessageDialog> _dialogQueue;
    private static readonly CancellationTokenSource _cancellationTokenSource;

    static MessageDialogDisplayer()
    {
        _dialogQueue = new ConcurrentQueue<MessageDialog>();
        _cancellationTokenSource = new CancellationTokenSource();

        new Task(DisplayQueuedDialogs, _cancellationTokenSource.Token).Start();
    }

    public static void DisplayDialog(MessageDialog dialog)
    {
        _dialogQueue.Enqueue(dialog);
    }

    private static async void DisplayQueuedDialogs()
    {
        const int millisecondsBetweenDialogChecks = 500;

        while (!_cancellationTokenSource.Token.IsCancellationRequested)
        {
            MessageDialog dialogToDisplay;
            if (_dialogQueue.TryDequeue(out dialogToDisplay))
            {
                await dialogToDisplay.ShowAsync();
            }
            else
            {
                await Task.Delay(millisecondsBetweenDialogChecks);
            }
        }
    }
}

这已将我的 try/catch 语句更改为

MessageDialog errorDialog = null;
try
{
    await DoSomething();
}
catch(InvalidOperation ex)
{
    MessageDialogDisplayer.DisplayDialog(new MessageDialog(ex.Message));
}
catch(CommunicationException)
{
    MessageDialogDisplayer.DisplayDialog(new MessageDialog(StringResourceLoader.LoginError));
}

从长远来看,这使事情变得更加稳定(一旦我将所有消息对话框调用者转换为使用它而不是showAsyncing它们自己)并使 try/catch 块不那么混乱(imo)。

于 2013-07-23T17:47:55.830 回答