我有这个方法
public void Execute(Action action)
{
try
{
action();
}
finally
{
}
}
我需要将它转换为像这样的异步方法调用
public async Task ExecuteAsync(Action action)
{
try
{
await action();
}
finally
{
}
}
上面代码的问题是编译器发出以下错误
等待'运算符只能在异步lambda中使用 表达。考虑使用' async'标记这个lambda表达式。 改性剂。
答案 0 :(得分:21)
如果您想在代理上await
,则必须是Func<Task>
或Func<Task<T>>
类型。 Action
等同于void Action()
命名方法。您无法等待void
,但您可以等待Task Func()
或Task<T> Func
:
public async Task ExecuteAsync(Func<Task> func)
{
try
{
await func();
}
finally
{
}
}
如果无法做到这一点,则意味着该方法内部并非真正异步,而您实际想要做的是在线程池线程上执行同步委托,这是另一回事,并且不是不是异步执行某些事情。在这种情况下,使用Task.Run
打包电话就足够了。
答案 1 :(得分:4)
试试这个:
public async void ExecuteAsync(Action action)
{
await Task.Run(action);
}
使用Task.Run()
通过在其他任务上运行您的操作来创建等待。
并且还要记住,处理“等待”的例外情况并不像intended那样有效。
更好地将action()
调用试着在该包装上捕获一个do Task.Run()
。
答案 2 :(得分:0)
让我们将您的起点简化为:
public void Execute(Action action)
{
action();
}
因为你说finally
并不重要。
有效但毫无意义:
public async Task ExecuteAsync(Action action)
{
action();
}
这与做的几乎相同:
public Task ExecuteAsync(Action action)
{
action();
return Task.FromResult(0);
}
也就是说,它会执行非异步执行的操作,然后返回“已完成”的任务,这样就无法获得任何内容。值得注意的是,从非异步转为异步通常是一个有效的分路点。
更好:
public async Task ExecuteAsync(Action action)
{
await Task.Run(() => action());
}
在这种情况下,因为它是一个单独的返回空值的调用可以简化为:
public async Task ExecuteAsync(Action action)
{
await Task.Run(action);
}
这是否值得做是另一回事。这会释放当前线程,但会转移到另一个线程来完成工作。如果我们在调用时只是等待它的结果,那么我们也可以调用非异步版本并完成它。但是,如果我们在调用者中执行WaitAll
,或者从中受益于此的其他内容,那么它确实可能有用。
可能会好得多:
public async Task ExecuteAsync(Action action)
{
await actionAsync();
}
这里有我们正在调用的方法的Async版本,所以我们改为使用它。现在,如果actionAsync
只是旋转一个线程或使用线程池,那么这可能与上面的相同。但是,如果actionAsync
使用异步I / O执行某些操作,则可以获得更大的好处。
请注意,在这种情况下,我们可以直接调用我们得到的任务:
public Task ExecuteAsync(Action action)
{
return actionAsync();
}
但是,如果我们需要在我们的方法中await
之后完成某些操作,那就不一样了。 E.g:
public void Execute(Action action)
{
action();
otherAction();
}
必须成为:
public async Task Exectute(Action action)
{
await actionAsync();
await otherActionAsync();
}
或者如果otherAction
没有异步版本:
public async Task Exectute(Action action)
{
await actionAsync();
otherAction();
}