4

キャッチされた例外のためにメッセージ ダイアログを表示する適切な方法は何ですか?

もともとやってみた

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

awaittry ブロック内では実行できないため、これは機能しませんでした。await コマンドを実行すると、コンパイラは次の警告を表示します。

この呼び出しは待機されていないため、呼び出しが完了する前に現在のメソッドの実行が続行されます。呼び出しの結果に「await」演算子を適用することを検討してください

これらの警告をコードに残しておくのは好きではありません。なぜなら、人々が使用するawaitのを忘れてバグを見つけるのが困難な場所がいくつかあるからです。

メッセージ ダイアログ ステートメントを に変更するvar task = new MessageDialog(ex.Message).ShowAsync().AsTask();と、すべての警告とエラーが取り除かれますが、それが適切な方法であるかどうかはわかりません (技術的にはawait、呼び出しを求めているのと同じ理由で悪いです)。

最後に、例外を保存し、ユーザーに表示するロジック (スローされた例外の種類を決定するすべてのロジックを含む) をキャッチの外で実行しようとしました。

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

編集: 他の問題についてのHansのコメントの後、次のクラスを作成して解決しました:

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 に答える