Convert a method method call to an asynchronous method call

I have this method

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

and I need to convert it to an async method call like this

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

The problem with the above code is that the compiler produces the following error

The wait statement can only be used in an asynchronous lambda expression. Consider labeling this lambda expression with the "async" modifier.

+8
c # asynchronous
source share
3 answers

If you want await for the delegate, it must be of type Func<Task> or Func<Task<T>> . Action equivalent to the void Action() method. You cannot wait on void , but you can wait for Task Func() or Task<T> Func :

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

If this cannot be done, it means that the method inside is not asynchronous, and what you really want to do is to execute the synchronous delegate in the thread-to-thread thread, which is another question, and isn really doing something asynchronously. In this case, ending the call with Task.Run will suffice.

+13
source share

Try the following:

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

Using Task.Run() creates an expectation by starting an action on another task. And also remember that exception handling on "awaitables" doesn't work like

+3
source share

Let me simplify the starting point to:

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

Because you say that finally not important.

Acceptable, but meaningless:

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

This will be almost the same as doing:

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

That is, he will do what non-async did, and then returns a “completed” task, so that nothing happens. This is worth noting, although often this is the real point-to-point transition from non-asynchronous to asynchronous.

it's better:

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

In this case, since one default return call can be simplified for it:

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

Whether it is worth it or not is another matter. This frees the current thread from use, but transfers it to another thread to do the work. If we just wait for the result of this when it will be called, then we could just name the non-asynchronous version and do it. If, however, we do WaitAll at the caller, or something else that, therefore, benefits from it, then it really can be useful.

Potentially much better, although there are:

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

There is an Async version of the method that we are calling, so we are changing to use this. Now it can be the same as above if actionAsync just spins a thread or uses a thread pool. If, however, actionAsync uses asynchronous I / O for something, then there is much more to it.

Please note that in this case we could only get the tail, called the Task, which we get:

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

However, this would not be the same if we needed something done after await inside our method. For example:.

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

It should become:

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

Or, if otherAction does not have an asynchronous version:

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

All Articles