Codectionary / Developer documentation / C#

Task & Task<T>

Task represents an asynchronous operation that may still be running, and Task<T> represents one that will eventually produce a value of type T. Tasks are the building block that async/await is built on top of - an async method actually returns a Task (or Task<T>) that the caller can await, check the status of, or attach continuations to.

Syntax

Task<T> task = SomeAsyncMethod();

Examples

Creating and Running a Task

Starting work on a separate task and awaiting its completion.

Task<int> CalculateAsync()
{
    return Task.Run(() =>
    {
        Thread.Sleep(500);  // simulate CPU-bound work
        return 6 * 7;
    });
}

int result = await CalculateAsync();
Console.WriteLine(result);  // 42

Task Status and Properties

Inspecting a task's state without necessarily awaiting it immediately.

Task<int> task = Task.Run(() =>
{
    Thread.Sleep(300);
    return 100;
});

Console.WriteLine(task.IsCompleted);  // false, probably still running

int result = await task;
Console.WriteLine(task.IsCompleted);   // true
Console.WriteLine(result);              // 100

Task.CompletedTask and Task.FromResult

Returning an already-completed task, useful for satisfying an async interface without real async work.

Task LogAsync(string message)
{
    Console.WriteLine(message);
    return Task.CompletedTask;  // no real async work needed, but interface requires Task
}

Task<int> GetCachedValueAsync(int cached)
{
    return Task.FromResult(cached);  // wraps an already-known value in a Task
}

await LogAsync("Started");
int value = await GetCachedValueAsync(99);
Console.WriteLine(value);

Best practices

  • Use Task.Run() specifically for offloading CPU-bound work to a background thread - it is not needed for naturally async I/O operations like HttpClient calls, which are already non-blocking
  • Prefer awaiting a Task directly over checking .IsCompleted in a polling loop - awaiting is more efficient and far simpler to reason about
  • Use Task.FromResult() or Task.CompletedTask when implementing an async interface method that has no real asynchronous work to do
  • Avoid using .Result or .Wait() to synchronously block on a Task - always prefer await, which does not risk deadlocks or block the calling thread

At a glance

Purpose
Applications on the .NET platform
File extension
.cs
Runs in
.NET runtime
Usually used with
.NET SDK and libraries

Specifications & further reading

Related C# documentation

async and await
The async and await keywords let you write asynchronous code that reads almost like ordinary sequential code. Marking a method async allows it to use await, which pauses execution at that point until the awaited operation completes, without blocking the calling thread - freeing it up to do other work in the meantime. This is essential for keeping applications responsive during I/O-bound work like network calls, file access, or database queries.
Task.WhenAll & Task.WhenAny
Task.WhenAll() lets you run multiple independent asynchronous operations concurrently and await all of them together, completing once every task finishes - much faster than awaiting them one at a time. Task.WhenAny() completes as soon as the first of several tasks finishes, useful for timeout patterns or taking whichever result arrives first.
CancellationToken
CancellationToken provides a standard, cooperative way to signal that an asynchronous operation should stop before it completes naturally. A CancellationTokenSource creates the token and controls when cancellation is requested; the token itself is passed into async methods, which check it periodically (or pass it to another cancellable operation) and can throw an OperationCanceledException to unwind cleanly.
Async Pitfalls: void vs Task, ConfigureAwait
A few recurring mistakes trip up many C# developers new to async: using async void instead of async Task (which makes exceptions impossible to catch normally), and blocking on async code with .Result or .Wait() (which can cause a deadlock in contexts with a synchronization context, like older ASP.NET or WPF apps). Understanding these pitfalls up front avoids some of the most common async-related bugs.