簡體   English   中英

async / await vs ContinueWith

[英]async/await vs ContinueWith

我在想,幾乎所有使用ContinueWith代碼都可以用async/await重構,但這個代碼有點難。 我要轉換的草圖:

// UI unit testing: close the message box in 1s

Task.Delay(1000).ContinueWith((t) => 
    {
        SendKeys.Send("{ENTER}"); 
    }, TaskScheduler.FromCurrentSynchronizationContext());

MessageBox.Show("Hello!");

Debug.Print("continue after a message box");

如何使用async/await

您可以將中間部分拆分為輔助異步方法:

        private async Task EnterAfterDelay()
        {
            await Task.Delay(1000);
            SendKeys.Send("{ENTER}");
        }

        private void MyMethod()
        {
            EnterAfterDelay();
            MessageBox.Show("Hello!");
            Debug.Print("continue after a message box");
        }

這揭示了原始代碼的問題,即繼續任務永遠不會被“等待”(在原始上下文中給出一個ContinueWith),這意味着它拋出的任何異常都將是未處理的。 理想情況下,你將它存儲在某個地方的Task變量中,並決定一個好的地方等待它並處理它拋出的任何異常。


一個簡短的說明:

無論使用哪種方法,如果用戶在第二個過去之前關閉消息框,{ENTER}將被發送到關閉后具有焦點的任何控件,這可能導致意外的操作,例如在任何活動的窗口上按下默認按鈕在啟動消息框之前。 如果打算創建一個自動消失但可以提前解散的彈出窗口,您可能只想創建一個提供所需行為的自定義窗口。

不完全是你的代碼,但你可以做這樣的事情(未經測試):

Func<Action, Task> doAsync = async (action) =>
{
    await Task.Yield();
    action();
};

var messageBoxTask = doAsync(() => 
    MessageBox.Show("Hello!"));

var delay = Task.Delay(1000);
var task = await Task.WhenAny(delay, messageBoxTask);

if (task != messageBoxTask)
{
    SendKeys.Send("{ENTER}")
    await messageBoxTask;
}

Debug.Print("continue after a message box");

我認為它非常接近。

您可以將任務抽象為方法,然后等待方法,如...

Task DelayTask() {
    return Task.Delay(1000);
}


await DelayTask();
SendKeys.Send("{ENTER}");
MessageBox.Show("Hello!");
Debug.Print("continue after a message box");

或者你可以像...那樣寫它

await Task.Delay(1000);
SendKeys.Send("{ENTER}");
MessageBox.Show("Hello!");
Debug.Print("continue after a message box");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM