TaskCompletionSource When to use SetResult versus TrySetResult, etc
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
The TaskCompletionSource class in the .NET framework provides a flexible way to create and control tasks manually. It's particularly useful in asynchronous programming when you need to manually signal that a task has completed, either successfully or with an error. This article delves into the importance of the TaskCompletionSource, and the distinction between using SetResult() versus TrySetResult() methods, among other things.
What is TaskCompletionSource?
TaskCompletionSource<TResult> is a pivotal class that provides the functionality to produce a Task that can be manually completed. It encapsulates an instance of a Task and allows its producer to control the task’s lifecycle:
- Set the result of the task.
- Set an exception that caused the task to fail.
- Signal task cancellation.
It is often used when integrating synchronous code with asynchronous patterns offered by async/await in C#.
SetResult() vs TrySetResult()
These methods are crucial for indicating the completion of a task. However, they serve slightly different purposes depending on your requirements for error handling and control over task states.
SetResult()
- Purpose: Directly sets the result of a task.
- Behavior: If you call
SetResult()on a task that is no longer in a pending state (originally awaiting completion), anInvalidOperationExceptionwill be thrown. - Use Case: It is used when you are certain that the task is in a valid state to be completed and do not want to handle states where the task might have already been completed, faulted, or canceled.
TrySetResult()
- Purpose: Attempts to set the result of the task.
- Behavior: Returns a boolean,
trueif the result was set successfully, otherwisefalsewithout throwing an exception. - Use Case: This method is particularly useful in scenarios where concurrent operations might try to complete the same task and you wish to handle any unsuccessful attempts gracefully.
Here's a comparison table for quick reference:
| Method | Throws on Error | Returns Success | Use When |
SetResult() | Yes | No | You are certain the task is still pending |
TrySetResult() | No | Yes | You want to attempt setting the result with checks |
Example Scenario
Consider a situation where you have a scenario with multiple asynchronous operations racing to complete. You may want to signal completion without having to worry about concurrency issues:
In the above example, using TrySetResult() prevents potential race conditions that could arise if multiple operations try to complete the task simultaneously.
Best Practices and Considerations
Exception Handling
- Always consider exceptions that may arise when using
SetResult(). - Use
TaskCompletionSourcein try-catch blocks to better handle exceptions and ensure the task’s lifecycle is controlled.
Cancellation and Exceptions
Apart from setting results, you should manage task cancellation and exception states:
- TrySetCanceled(): Use to signal task cancellation. Preferably in scenarios where task may already have transitioned state or where cancelation logic is complex.
- TrySetException(): Use to signal an error has occurred. Essential in error-handling contexts where you wish to encapsulate the exception in the task.
Thread Safety
Note that TaskCompletionSource is generally thread-safe for setting results, exceptions, and cancellation, making TrySet* methods more reliable in multithreading applications.
Conclusion
TaskCompletionSource offers robust control over the operation of asynchronous tasks. Whether you use SetResult() or TrySetResult() depends on your specific needs for error handling and concurrency. Recognizing scenarios and employing the correct method is crucial to ensuring the stability and reliability of your asynchronous code.
Understanding the nuances of these methods and when to use each effectively requires careful consideration, especially in complex, multithreaded environments. Asynchronous programming, when architected correctly using tools like TaskCompletionSource, becomes an invaluable strategy for performant and scalable applications.
Related reading
- Task.Delay0 not asynchronous
- Task.Delay in .net fires 125ms early
- Task.Factory.StartNew followed by Task.Wait
- Task.Factory.StartNew vs Task.Factory.FromAsync
- Task.Run and UI Progress Updates
- Task.StartOrRestartWhenPossible
- Task.WaitAll is not waiting - Explanation
- Task.WhenAll - does it create a new thread?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.