Task.FromResult
C#
asynchronous programming
.NET
async-await

What is the use for Task.FromResultTResult?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Task.FromResult is used when a method must return Task-based output but the value is already available synchronously. It creates a completed Task with minimal overhead and avoids unnecessary async state machines. This makes APIs consistent without pretending work is asynchronous when it is not.

What Task.FromResult Returns

Task.FromResult returns an already-completed Task containing the provided result value.

csharp
1using System.Threading.Tasks;
2
3public static Task<int> GetDefaultPageSizeAsync()
4{
5    // Value is known immediately.
6    return Task.FromResult(50);
7}

Callers can still await this method like any other async-friendly API.

csharp
int size = await GetDefaultPageSizeAsync();

This is useful when an interface contract expects asynchronous methods across implementations.

Practical Use Cases

One common use case is caching. If data is already in memory, return it immediately as a completed task.

csharp
1using System.Collections.Concurrent;
2using System.Threading.Tasks;
3
4public sealed class UserCache
5{
6    private readonly ConcurrentDictionary<int, string> _names = new();
7
8    public Task<string?> GetNameAsync(int userId)
9    {
10        _names.TryGetValue(userId, out var name);
11        return Task.FromResult(name);
12    }
13}

Another use case is test doubles. Mock implementations can satisfy async contracts without creating fake delays.

csharp
1using System.Threading.Tasks;
2
3public interface IClock
4{
5    Task<long> GetUnixSecondsAsync();
6}
7
8public sealed class FakeClock : IClock
9{
10    public Task<long> GetUnixSecondsAsync() => Task.FromResult(1700000000L);
11}

Task.FromResult Versus async Methods

If you write an async method that immediately returns a constant, the compiler creates an async state machine that is unnecessary.

csharp
1// Less efficient for this trivial case.
2public async Task<int> GetStatusCodeAsync()
3{
4    return 200;
5}
6
7// Preferred.
8public Task<int> GetStatusCodeFastAsync()
9{
10    return Task.FromResult(200);
11}

For hot paths called frequently, this difference can matter.

Use the right helper for the right completion state.

  • Task.FromResult for successful completed results.
  • Task.FromException for faulted completed tasks.
  • Task.FromCanceled for canceled completed tasks.
csharp
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4
5public static Task<string> LoadConfigAsync(bool fail, CancellationToken token)
6{
7    if (token.IsCancellationRequested)
8        return Task.FromCanceled<string>(token);
9
10    if (fail)
11        return Task.FromException<string>(new InvalidOperationException("Config missing"));
12
13    return Task.FromResult("ok");
14}

These helpers make completion semantics explicit and predictable.

Interface Design Consistency

Large codebases often expose repository and service methods as asynchronous APIs, even when some implementations are memory-only. Returning Task.FromResult keeps signatures consistent so callers can use the same await-based flow regardless of backing store. This consistency becomes valuable when a memory implementation later moves to network or database access. The calling code does not change, and only internals are swapped. That is a practical architectural reason to use completed tasks in synchronous implementations while preserving long-term API flexibility.

Testing and Benchmark Considerations

When optimizing service methods, benchmark realistic call patterns before changing asynchronous signatures. In many applications, returning a completed task from lightweight methods reduces allocations and improves throughput. Unit tests should also verify that callers can still await these methods and receive expected values consistently under concurrency.

Common Pitfalls

A frequent mistake is using Task.FromResult for operations that are actually I/O bound. If data comes from network or disk, use real async APIs instead.

Another issue is wrapping expensive synchronous work in Task.FromResult. The work still blocks the calling thread before the task is created.

Developers also overuse Task.Run to mimic asynchrony for trivial results. If no background work is needed, Task.FromResult is cleaner and cheaper.

A final problem is returning null task references by mistake. Return Task.FromResult<object?>(null) or typed equivalents, not a null task object.

Summary

  • Task.FromResult creates an already-completed successful task.
  • It is ideal when result values are available immediately.
  • It avoids unnecessary async state machine overhead.
  • Use related completion helpers for exception and cancellation states.
  • Do not use it to hide real I/O or expensive synchronous work.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track 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.

Browse interview questions

All Rights Reserved.