[英]Using await inside a ContinueWith() block
我有以下代碼:
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith((answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
Task<bool> asyncTask = ExecuteAsyncFunc();
//asyncTask.Unwrap(); ??
asyncTask.ContinueWith((a) =>
{
// More
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
像這樣在其他地方調用:
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
我相信我需要調用Unwrap(),我試過,因為我在ContinueWith()
塊中調用await。 但是,當我取消注釋時,我收到以下錯誤:
錯誤CS1929'Task'不包含'Unwrap'的定義,最好的擴展方法重載'TaskExtensions.Unwrap(Task)'需要'Task'類型的接收器
我是否需要在此上下文中使用Unwrap,如果是這樣,我做錯了什么?
簡短的回答是使用await
而不是ContinueWith
:
var result = MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (answer == MessageBoxResult.Yes)
{
var a = await ExecuteAsyncFunc();
// More
}
很長的答案是, ContinueWith
有一些危險的默認選項(包括使用環境TaskScheduler
) ,並且await
自動為您正確地執行所有操作。 我在博客上詳細介紹了一下。
我是否需要在此上下文中使用Unwrap,如果是這樣,我做錯了什么?
你需要Unwrap
,只有當你的返回類型是一個Task<Task>
,和你真正想做的事與內任務的東西。
例如:
Task<Task> exampleTask = Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
});
如果我想實際上異步等待內部Task
,我會調用Unwrap
並await
:
Task exampleTask = await Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
}).Unwrap();
如果由於任何原因你想要await
你的繼續返回的任何任務,或者想要監視內部任務,那么你打電話給Unwrap
。 這里沒有必要這樣做。
你正在做的只是在你的ContinueWith
調用異步方法,但似乎你根本不想await
結果。
我建議盡可能使用async-await
來減少ContinueWith
的冗長。 將這兩者混合在一起通常會產生不良結果,因為事情變得相當復雜。 重構該代碼結果更清晰,更少的圈復雜度:
var result = await MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed",
MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
bool answer = await ExecuteFuncAsync();
}
你說由於你在ContinueWith
使用await,你必須打電話給unwrap; 我實際上並沒有看到你使用等待。 我認為你的意思是你想等待但不確定如何,因此需要解開思考。 如果是這種情況,那么你想要的只是使你的嵌套任務等待。 您可以通過使您提供的委托async
var result = MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo)
.ContinueWith(async (answer) =>
{
if (answer.Result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
}
}, TaskContinuationOptions.OnlyOnRanToCompletion);
public async Task<bool> ExecuteAsyncFunc()
{
await CallAnotherAsyncFunction();
}
這允許您在ContinueWith調用內等待委托內,而不必處理解包。
如果您要對任務執行任何操作,例如在不解包的情況下返回它,那么這是正確的方法。
public Task<BoolOrSomeOtherReturnType> Foo()
{
return MessageBoxHelper.MsgBox
.ShowAsync /* Continue with etc here */
}
但是如果你要在Foo
方法中對結果采取行動,那么就沒有必要使用ContinueWith,等待它。
public async Task<bool> Foo()
{
var result = await MessageBoxHelper.MsgBox
.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
await ExecuteAsyncFunc();
return true;
}
return false;
}
這簡化了你的代碼安靜一點。 另一件需要注意的是,您的ExecuteAsyncFunc()
方法不會對返回值起作用。 你只需等待,別無所求。
我注意到你沒有返回true / false,所以我假設有更多的代碼,為了清楚起見,你只是省略了。 如果不是這種情況,您可以節省一些開銷,只需返回任務,允許有人進一步向上調用它來代替它。 如果您對CallAnotherAsyncFunction
的調用返回Task<bool>
那么您也可以以相同的方式返回該調用。 您只需要等待,如果您必須阻止該方法繼續進行,以便您可以對等待方法的結果作出反應。 如果您不必,只需返回任務。
public Task<bool> ExecuteAsyncFunc()
{
return CallAnotherAsyncFunction();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.