Developers often use async methods in C# Asynchronous Programming to improve the throughput of applications. In this article, we will learn about the usage of three different statements in C# async methods. When working with asynchronous programming in C#, developers may encounter these constructs that serve distinct purposes. Understanding their use case is vital to writing clear and efficient asynchronous code.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Using Task.CompletedTask in Async Methods

Assuming we want to adhere to the asynchronous programming pattern. Let’s consider a method that only returns a task without actually performing any asynchronous work. 

In this case, we can use Task.CompletedTask. It’s similar to saying, “We have completed the task, and here’s a task to indicate the completion.”

Let’s create the TaskCompletedHandler class to understand this:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public class TaskCompletedHandler
{
    public Task UseTaskCompletedAsync()
    {
        Console.WriteLine("Not performing any asynchronous work.");

        return Task.CompletedTask;
    }
}

By using Task.CompletedTask in the UseTaskCompletedAsync() method, we avoid unnecessary overhead and resource consumption, as we’re only writing to the console and returning an already completed task without additional processing.

Although Task.CompletedTask is often used in asynchronous methods, it can be useful in synchronous methods as well to maintain consistency in method signatures, especially when we have both asynchronous and synchronous versions of a method.

Let’s see what a synchronous counterpart of our method looks like:

public void UseTaskCompletedSync()
{
    Console.WriteLine("Not performing any asynchronous work.");

    Task.CompletedTask.Wait(); 
}

We are able to ensure consistency in the UseTaskCompletedSync() method by using a void return type and performing synchronous work as well.

We use Task.CompletedTask.Wait() in our method, however, using it in a synchronous method isn’t a recommended practice, as it can lead to blocking the current thread, defeating the purpose of asynchronous programming.

Recognizing that blocking threads in synchronous contexts can lead to real-world performance and scalability issues is critical.

Using Task.FromResult in Async Methods

The Task.FromResult is a sibling to Task.CompletedTask. It is a useful method in async programming to create a completed Task with a specific result. It also allows us to quickly return a completed Task in situations where we don’t have asynchronous operations.

Let’s create the UseTaskFromResultAsync() method to understand this:

public async Task<string> UseTaskFromResultAsync()
{
    Console.WriteLine("Not performing any asynchronous work but returning a result.");

    var message = "Hello, world!";

    return await Task.FromResult(message);
}

Using Task.FromResult in the UseTaskFromResultAsync() method allows us to return a string result with the Task. Additionally, we use Task<string> in our method signature rather than Task.

In synchronous methods, we could also potentially use Task.FromResult, however, its usage might not align with the typical intention of synchronous methods:

public string UseTaskFromResultSync()
{
    Console.WriteLine("Not performing any asynchronous work but returning a result.");

    var message = "Hello, world!";

    return Task.FromResult(message).Result;
}

When we remove the async and Task keywords that we had in the last code block, we need to remove the await keyword also so that we don’t get a compiler error.

Here we need to get the result value of our task by using the Result property as we did in the UseTaskFromResultSync() method. In this method, we use Task.FromResult to return a completed Task<string>. Note that using Result is not advised for the same reasons as the Wait() method. 

Using Return Statements in Async Methods

On the other hand, if our asynchronous method does perform actual asynchronous work, we’ll use the return statement. This will signify an ongoing asynchronous operation. Therefore, the caller is notified that we are working asynchronously, with a task representing progress and completion.

Let’s create the UseReturnAsync() method and see how we can achieve this using a return statement:

public class ReturnHandler
{
    public async Task<int> UseReturnAsync()
    {
        Console.WriteLine("About to perform some asynchronous work.");

        await Task.Delay(1000);

        return 20;
    }
}

In the UseReturnAsync() method, we write a message to the console, carry out an asynchronous operation, and then return a task representing the completion of that operation. The caller can await this task to wait for the result.

When using the return statement in an asynchronous method, the method execution is temporarily paused until the awaited operation completes.

The return keyword is used in a similar way in both synchronous and asynchronous methods to provide a value as the result of the method. Whether the method is synchronous or asynchronous, the basic purpose of the return keyword remains the same – to send a value back from the method to the calling code.

Conclusion

In this article, we learned the usage of Task.CompletedTask,Task.FromResult and return in C# asynchronous methods. We also delved a little into their usage in a synchronous method.

In a nutshell, developers employ Task.CompletedTask when our method doesn’t perform actual asynchronous work but still needs to provide a completed task. We use Task.FromResult in a manner similar to Task.CompletedTask but include a result.

On the other hand, the return statement is used when our method performs asynchronous operations and returns a task representing their completion.

By grasping the usage and distinction between these constructs, we can write concise and efficient asynchronous codes.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!