我有以下代码:
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&#39;任务&#39;不包含&#39; Unwrap&#39;的定义 和最好的扩展方法重载 &#39; TaskExtensions.Unwrap(任务)&#39;需要一个类型的接收器 &#39;任务&#39;
我是否需要在此上下文中使用Unwrap,如果是,我做错了什么?
答案 0 :(得分:4)
简短的回答是使用await
代替ContinueWith
:
var result = MessageBoxHelper.MsgBox.ShowAsync("Press Yes to proceed", MessageBoxButton.YesNo);
if (answer == MessageBoxResult.Yes)
{
var a = await ExecuteAsyncFunc();
// More
}
答案很长,ContinueWith
has some dangerous default options (including using an ambient TaskScheduler
)和await
会自动为您正确执行所有操作。我在博客上详细介绍了。
答案 1 :(得分:3)
我是否需要在此上下文中使用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();
}
答案 2 :(得分:2)
你说由于你在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();
}