简体   繁体   English

将Action方法调用转换为异步Action方法调用

[英]Converting Action method call to async Action method call

I've this method 我有这个方法

public void Execute(Action action)
{
    try
    {
        action();
    }
    finally
    {
    }
}

and I need to convert it to an async method call like this one 我需要将它转换为像这样的异步方法调用

public async Task ExecuteAsync(Action action)
{
    try
    {
        await action();
    }
    finally
    {
    }
}

The problem with the code above is that the compiler issue the following error 上面代码的问题是编译器发出以下错误

The 'await' operator can only be used within an async lambda expression. 'await'运算符只能在异步lambda表达式中使用。 Consider marking this lambda expression with the 'async' modifier. 考虑使用'async'修饰符标记此lambda表达式。

If you want to await on a delegate, it has to be of type Func<Task> or Func<Task<T>> . 如果要await委托,则必须是Func<Task>Func<Task<T>> An Action is equivalent into a void Action() named method. Action等效于void Action()命名方法。 You can't await on void , yet you can await Task Func() or Task<T> Func : 你无法等待void ,但你可以等待Task Func()Task<T> Func

public async Task ExecuteAsync(Func<Task> func)
{
    try
    {
        await func();
    }
    finally
    {
    }
}

If this can't be done, it means that internally the method isn't truly asynchronous, and what you actually want to do is execute the synchronous delegate on a thread-pool thread, which is a different matter, and isn't really executing something asynchronously. 如果无法做到这一点,则意味着内部方法并非真正异步,而您实际想要做的是在线程池线程上执行同步委托,这是另一回事,并不是真的异步执行某些事情。 In that case, wrapping the call with Task.Run will suffice. 在这种情况下,使用Task.Run包装调用就足够了。

Try this: 试试这个:

public async void ExecuteAsync(Action action)
{
    await Task.Run(action); 
}

Using Task.Run() creates an awaitable by running your action on a different task. 使用Task.Run()通过在不同的任务上运行您的操作来创建等待。 And also bear in mind that handling exceptions on "awaitables" does not work as intended . 并且还要记住,处理“等待”的例外情况并不符合预期

Better wrap that action() call in a try catch an do Task.Run() on that wrapper. 更好地在try中捕获action()调用,在该包装上捕获do Task.Run()

Let's simplify your starting point down to: 让我们简化您的起点到:

public void Execute(Action action)
{
  action();
}

Because you say the finally isn't important. 因为你说finally并不重要。

Valid but pointless: 有效但毫无意义:

public async Task ExecuteAsync(Action action)
{
    action();
}

This will be pretty much the same as doing: 这与做的几乎相同:

public Task ExecuteAsync(Action action)
{
  action();
  return Task.FromResult(0);
}

That is, it'll do what the non-async was doing, and then return a "completed" Task so nothing is gained. 也就是说,它会执行非异步正在执行的操作,然后返回“已完成”的任务,这样就无法获得任何内容。 It's worth noting though as it's often a valid part-way-point in moving from non-async to async. 值得注意的是,它通常是从非异步转为异步的有效部分点。

Better: 更好:

public async Task ExecuteAsync(Action action)
{
  await Task.Run(() => action()); 
}

Which in this case, because it's a single void-returning call can be simplified to: 在这种情况下,因为它是一个单独的void返回调用可以简化为:

public async Task ExecuteAsync(Action action)
{
  await Task.Run(action); 
}

Whether this is worth doing or not is another matter. 这是否值得做是另一回事。 This releases the current thread from being used, but transfers to another thread to do the work. 这会释放当前线程,但会转移到另一个线程来完成工作。 If we're just going to await the result of this when it's called then we might as well just call the non-async version and be done with it. 如果我们在调用时只是等待它的结果,那么我们也可以调用非异步版本并完成它。 If however we're doing WaitAll in the caller, or something else that hence benefits from this, then it could indeed be useful. 但是,如果我们在调用者中执行WaitAll ,或者从中受益于此的其他东西,那么它确实可能有用。

Potentially much better though is: 可能更好的是:

public async Task ExecuteAsync(Action action)
{
  await actionAsync();
}

Here there's an Async version of the method we are calling, so we change to make use of that. 这里有我们调用的方法的Async版本,所以我们改为使用它。 Now, that could be just the same as the above if actionAsync just spins up a thread or uses the thread pool. 现在,如果actionAsync只是旋转一个线程或使用线程池,那么这可能与上面的相同。 If however actionAsync does something using asynchronous I/O then there's a much bigger benefit to this. 但是,如果actionAsync使用异步I / O执行某些操作,那么这将带来更大的好处。

Note that in this case we could have just tail-called the Task we get: 请注意,在这种情况下,我们可以直接调用我们获得的任务:

public Task ExecuteAsync(Action action)
{
  return actionAsync();
}

However, that wouldn't be the same if we needed something done after an await within our method. 但是,如果我们需要在我们的方法中await之后完成某些事情,那就不一样了。 Eg: 例如:

public void Execute(Action action)
{
  action();
  otherAction();
}

Would have to become: 必须成为:

public async Task Exectute(Action action)
{
  await actionAsync();
  await otherActionAsync();
}

Or if otherAction had no async version: 或者如果otherAction没有异步版本:

public async Task Exectute(Action action)
{
  await actionAsync();
  otherAction();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM