在 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。但是,当我取消注释时出现以下错误:
Error CS1929 'Task' does not contain a definition for 'Unwrap'
and the best extension method overload
'TaskExtensions.Unwrap(Task)' requires a receiver of type
'Task'
我是否需要在此上下文中使用 Unwrap,如果需要,我做错了什么?
你说你必须调用 unwrap 因为你在 ContinueWith
中使用了 await;我实际上并没有看到你使用等待。我假设你的意思是你想等待但不确定如何等待,因此需要考虑展开。如果是这种情况,那么您想要的只是让您的嵌套任务可等待。您可以通过让您提供的代表 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 调用中,而不必处理展开。
如果您打算对 Task 做任何事情,例如 return 它不展开,那么这是正确的方法。
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()
方法不会作用于 return 值。您只需等待,什么都不做。
我注意到您没有 returning true/false,所以我假设您为了清楚起见省略了更多代码。如果不是这种情况,您可以节省一些开销,只需 return 任务,让调用堆栈更上层的人等待它。如果您调用 CallAnotherAsyncFunction
returns Task<bool>
那么您也可以 return 以相同的方式调用。只有在必须阻止该方法继续执行时才需要等待,以便您可以对等待方法的结果做出反应。如果不需要,只需 return 任务。
public Task<bool> ExecuteAsyncFunc()
{
return CallAnotherAsyncFunction();
}
Do I need to use Unwrap in this context, and if so, what am I doing
wrong?
只有当您的 return 类型是 Task<Task>
并且您确实想对内部任务做一些事情时,您才需要 Unwrap
。
例如:
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
从你的延续中 return 任何任务,或者想要监控内部任务,那么你会调用 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();
}
简短的回答是使用 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
会自动为您正确完成所有事情。我会在我的博客上详细介绍。
我有以下代码:
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。但是,当我取消注释时出现以下错误:
Error CS1929 'Task' does not contain a definition for 'Unwrap' and the best extension method overload 'TaskExtensions.Unwrap(Task)' requires a receiver of type 'Task'
我是否需要在此上下文中使用 Unwrap,如果需要,我做错了什么?
你说你必须调用 unwrap 因为你在 ContinueWith
中使用了 await;我实际上并没有看到你使用等待。我假设你的意思是你想等待但不确定如何等待,因此需要考虑展开。如果是这种情况,那么您想要的只是让您的嵌套任务可等待。您可以通过让您提供的代表 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 调用中,而不必处理展开。
如果您打算对 Task 做任何事情,例如 return 它不展开,那么这是正确的方法。
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()
方法不会作用于 return 值。您只需等待,什么都不做。
我注意到您没有 returning true/false,所以我假设您为了清楚起见省略了更多代码。如果不是这种情况,您可以节省一些开销,只需 return 任务,让调用堆栈更上层的人等待它。如果您调用 CallAnotherAsyncFunction
returns Task<bool>
那么您也可以 return 以相同的方式调用。只有在必须阻止该方法继续执行时才需要等待,以便您可以对等待方法的结果做出反应。如果不需要,只需 return 任务。
public Task<bool> ExecuteAsyncFunc()
{
return CallAnotherAsyncFunction();
}
Do I need to use Unwrap in this context, and if so, what am I doing wrong?
只有当您的 return 类型是 Task<Task>
并且您确实想对内部任务做一些事情时,您才需要 Unwrap
。
例如:
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
从你的延续中 return 任何任务,或者想要监控内部任务,那么你会调用 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();
}
简短的回答是使用 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
会自动为您正确完成所有事情。我会在我的博客上详细介绍。