簡體   English   中英

在ContinueWith()塊中使用await

[英]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 ,我會調用Unwrapawait

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.

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