C# TaskCompletionSource — Complete Guide
In this tutorial, you'll learn about C# TaskCompletionSource. We cover key concepts, practical examples, and best practices.
You have an event-based API (like a socket or a legacy library) that raises an event when done. You want to await its completion instead of using callbacks. TaskCompletionSource<T> creates a Task<T> that you manually control — completing or faulting it as needed.
Wrong
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(host, port, ar =>
{
socket.EndConnect(ar);
// Now we're connected, but we can't await this
OnConnected(); // Callback-based
}, null);
Output: Works, but the caller must use callbacks or events, leading to callback nesting.
Right
public Task ConnectAsync(string host, int port)
{
var tcs = new TaskCompletionSource();
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(host, port, ar =>
{
try
{
socket.EndConnect(ar);
tcs.SetResult(); // Signal completion
}
catch (Exception ex)
{
tcs.SetException(ex); // Signal error
}
}, null);
return tcs.Task;
}
// Usage
await ConnectAsync("example.com", 80);
Output: The event-based APM pattern is wrapped in a clean Task-based API.
TaskCompletionSource supports cancellation, multiple continuations, and running continuations synchronously.
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
Prevention
- Use
TaskCompletionSource<T>to bridge old asynchronous patterns (APM, EAP) to Task-based. - Use
TaskCompletionSourcefor manual task lifecycle control (e.g., in tests). - Use
TaskCompletionSource.RunContinuationsAsynchronouslyto avoid reentrancy issues. - Set result on a captured
SynchronizationContextif the consumer needs UI thread access. - Always use
try-catchin the callback to propagate exceptions viaSetException. - Use
TaskCompletionSource.SetCanceled()in cancellation scenarios.
Common Mistakes with task completed source
- Misunderstanding that
Stringis[Char]with poor performance for large text operations - Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging
These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
TaskCompletionSource is used in Doda Browser to bridge native messaging callbacks to async await. For more C# async, visit DodaTech.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro