简体   繁体   中英

How to convert a void synchronous method to async method?

So I have this method that has only synchronous operations:

public void Foo(){
    //do something synchronously
    if(x == 0)
        return;
    else if(x < 5):
        //do something
        return;
    // do something extra
}

Due to some interface changes, that method has to be changed to asynchronous, despite having no async operations. And in order to have the async keyword, there must be an await keyword within its body. Would an equivalent method of the originally synchronous method be:

public async Task FooAsync(){
    //do something synchronously
    if(x == 0)
        await Task.CompletedTask;
    else if(x < 5):
        //do something
        await Task.CompletedTask;
    // do something extra
}

I'm not sure about this since the CompletedTask property indicates that it is a successful operation, which isn't the case for all these conditionals.

EDIT: Resolved in comments. Just because a method is denoted with an "async" suffix it does not mean that it needs an async modifier. The function would be written as shown below to adhere to interface changes:

public Task FooAsync(){
    //do something synchronously
    if(x == 0)
        return Task.CompletedTask;
    else if(x < 5):
        //do something
        return Task.CompletedTask;
    // do something extra
    return Task.CompletedTask;
}

As others have noted, a task-like return type is an asynchronous signature , whereas async is an asynchronous implementation detail . It's entirely possible to have a Task -returning method not be async .

However, there is one important caveat: exceptions. When an asynchronous (ie, Task -like-returning) method fails, the expected semantics is to capture the exception and place it on the returned task.

So, you wouldn't want to just return CompletedTask ; you'd also want to capture exceptions and use Task.FromException :

public Task FooAsync()
{
  try
  {
    //do something synchronously
    if(x == 0)
        return Task.CompletedTask;
    else if(x < 5):
        //do something
        return Task.CompletedTask;
    // do something extra
    return Task.CompletedTask;
  }
  catch (Exception ex)
  {
    return Task.FromException(ex);
  }
}

At this point, there's rather a bit of boilerplate. You may prefer to use async without await , as such:

#pragma warning disable 1998
public async Task FooAsync()
#pragma warning restore 1998
{
    //do something synchronously
    if(x == 0)
        return;
    else if(x < 5):
        //do something
        return;
    // do something extra
}

The problem with that approach is that you will get compiler warnings unless you include the ugly pragmas to disable them. If you find yourself needing to do this in several places, I would recommend using some helper methods ( stolen from my AsyncEx library ):

public static class TaskHelper
{
#pragma warning disable 1998
    public static async Task ExecuteAsTask(Action func)
#pragma warning restore 1998
    {
        func();
    }

#pragma warning disable 1998
    public static async Task<T> ExecuteAsTask<T>(Func<T> func)
#pragma warning restore 1998
    {
        return func();
    }
}

used as such:

public Task FooAsync() => TaskHelper.ExecuteAsTask(() =>
{
    //do something synchronously
    if(x == 0)
        return;
    else if(x < 5):
        //do something
        return;
    // do something extra
});

which allows you to wrap synchronous methods quickly and easily.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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