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(); }