Zol*_*yak 1 c# action asynchronous async-await
假设我们有一个像这样的动作执行包装器:
private void ExecuteAction(Action action)
{
Console.WriteLine($"starting action ...");
action();
Console.WriteLine($"finished action ...");
}
Run Code Online (Sandbox Code Playgroud)
假设我们这样称呼它:
ExecuteAction( async () => { ... } ); // 1
Run Code Online (Sandbox Code Playgroud)
或者像这样:
ExecuteAction( () => { ... } ); // 2
Run Code Online (Sandbox Code Playgroud)
我想知道这两个调用有什么区别以及ExecuteAction()方法内部如何处理?有什么区别吗?
在这里使用Action委托将转化为async void众所周知的反模式(有例外)。
请注意,async关键字不是签名的一部分。await它是一个实现细节,允许在方法内部使用。
所以,ExecuteAction这没有什么区别。它看到的只是一个void Action()代表。使用它就像ExecuteAction( async () => { await SomethingAsync(); });我在上面链接的文章中列出的所有陷阱和缺点一样。(tl;dr:真的不建议这样做)
另请参阅有关关键字本身的文档:
空白。通常不建议将 async void 方法用于事件处理程序以外的代码,因为调用者无法等待这些方法,并且必须实现不同的机制来报告成功完成或错误条件。
如果您想向观众提供同步和异步体验,您可以执行以下操作:
// your already known implementation
private void ExecuteAction(Action action)
{
// ...
}
/// <summary>Async Version</summary>
/// <example>
/// Usage:
/// <code>
/// await ExecuteAsync( () => { ... } );
/// </code>
/// or
/// <code>
/// await ExecuteAsync( async () => { ... await SomethingAsync(); ... } );
/// </code>
/// </example>
private async Task ExecuteAsync(Func<Task> asyncAction)
{
// Before client-defined function code goes here
await asyncAction();
// After client-defined function code goes here
}
Run Code Online (Sandbox Code Playgroud)
如果需要,您还可以传递一个状态对象并避免它被捕获:
/// <example>
/// <code>
/// await ExecuteAsync( o => { ... }, someStateObject );
/// </code>
/// </example>
private async Task ExecuteAsync(Func<object,Task> asyncAction, object state = null)
{
await asyncAction(state);
}
Run Code Online (Sandbox Code Playgroud)
提供异步 API,我也总是有机会传递CancellationToken:
/// <example>
/// <code>
/// await ExecuteAsync( o => { ... }, someStateObject, cancel );
/// </code>
/// </example>
private async Task ExecuteAsync(Func<object, CancellationToken, Task> asyncAction, object state = null, CancellationToken token = default)
{
await asyncAction(state, token);
}
Run Code Online (Sandbox Code Playgroud)
如果这与 GUI 相关,您还可以考虑报告进度:
/// <example>
/// <code>
/// await ExecuteAsync( o => { ... }, someStateObject, p => { ... },cancel );
/// </code>
/// </example>
private async Task ExecuteAsync<TProgress>(
Func<object, IProgress<TProgress>, CancellationToken, Task> asyncAction,
object state = null,
IProgress<TProgress> progress = null,
CancellationToken token = default)
{
await asyncAction(state, progress, token);
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以使状态对象类型安全
private async Task ExecuteAsync<TState, TProgress>(
Func<TState, IProgress<TProgress>, CancellationToken, Task> asyncAction,
TState state = null,
IProgress<TProgress> progress = null,
CancellationToken token = default)
{
await asyncAction(state, progress, token);
}
Run Code Online (Sandbox Code Playgroud)
资料来源:
Async/Await - 异步编程的最佳实践 # 避免 Async Void - Stephen Cleary,2013 年 3 月,MSDN 杂志