4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Task.FromResult の使い方と活用方法

Posted at

Task.FromResult の使い方と活用方法

C# で非同期プログラミングをする際、 Task.FromResult<T> は非常に便利なメソッドです。本記事では Task.FromResult<T> の基本的な使い方や実際の活用方法、さらには適切な場面と注意点について詳しく解説します。


1. Task.FromResult<T> とは?

Task.FromResult<T> の基本

Task.FromResult<T> は、指定した値を返す すでに完了している Task<T> を即座に作成 するための静的メソッドです。

Task<T> Task.FromResult<T>(T result)

これにより、非同期メソッドの戻り値として Task<T> を求められた場合でも、明示的に async/await を使わずに結果を即座に返すことができます。

例えば、以下のコードは Task<int> を即座に返します。

Task<int> task = Task.FromResult(42);

この task はすでに完了しており、await するとすぐに 42 を得ることができます。


2. Task.FromResult<T> を使うべき場面

(1) 非同期メソッドで即座に結果を返したい場合

非同期メソッド (async メソッド) の戻り値が Task<T> である場合、処理結果がすぐに分かっているなら Task.FromResult<T> を使うことで、オーバーヘッドを減らし効率を上げることができます。

例:キャッシュデータがある場合

private Dictionary<int, string> _cache = new();

public Task<string> GetDataAsync(int id)
{
    if (_cache.TryGetValue(id, out var cachedData))
    {
        return Task.FromResult(cachedData); // キャッシュがあれば即座に返す
    }
    return FetchFromDatabaseAsync(id); // キャッシュがなければDBから取得
}

この方法により、キャッシュがある場合は Task.Run のような不要なスレッド生成をせず、即座に結果を返すことができます。


(2) 非同期メソッドのモックを作成する場合

Task.FromResult<T> は、ユニットテストで非同期メソッドの戻り値をモックする のにも適しています。

例:Moq を使った非同期メソッドのモック

var mockService = new Mock<IMyService>();
mockService.Setup(s => s.GetValueAsync()).Returns(Task.FromResult("Mocked Value"));

これにより、非同期メソッド GetValueAsync が呼ばれた際に、実際の処理をせず即座に "Mocked Value" を返すようになります。これによってテストの実行速度を向上させることができます。


(3) インターフェースのシグネチャを統一する場合

Task.FromResult<T> を使用すると、同期的に完了する処理を非同期メソッドの形にする ことができます。

例:非同期インターフェースの実装

public interface IUserService
{
    Task<User> GetUserAsync(int id);
}

public class MockUserService : IUserService
{
    public Task<User> GetUserAsync(int id)
    {
        return Task.FromResult(new User { Id = id, Name = "Test User" });
    }
}

このように、同期的な処理を Task<T> でラップすることで、非同期APIとの統一性を保つことができます。


3. Task.FromResult<T> の注意点

(1) 長時間の処理には向かない

Task.FromResult<T>非同期処理を実行するわけではない ため、長時間の処理には適しません。そのような場合は Task.Run を使用するのが適切です。

悪い例:重い処理を Task.FromResult で返す

public Task<int> GetSlowResultAsync()
{
    return Task.FromResult(SlowComputation()); // メインスレッドをブロックする
}

上記の SlowComputation() が重い処理である場合、メインスレッドをブロックするため、非同期処理のメリットが失われます。

適切な方法:Task.Run を使う

public Task<int> GetSlowResultAsync()
{
    return Task.Run(() => SlowComputation()); // 別スレッドで実行
}

(2) 例外処理に注意

Task.FromResult<T> を使うと、発生した例外は即座にスローされる ため、例外を非同期に伝播させる場合は Task.FromException を使うべきです。

例:非同期メソッドでエラーを返す場合

public Task<int> GetErrorAsync()
{
    return Task.FromException<int>(new InvalidOperationException("エラーが発生しました"));
}

こうすることで、非同期処理において await した際に try-catch で適切に例外を処理できます。


4. まとめ

用途 適切な方法
即座に結果を返す Task.FromResult(42) を使用
キャッシュがある場合 Task.FromResult でキャッシュデータを返す
非同期メソッドのモック Returns(Task.FromResult(value)) を使う
非同期APIのシグネチャ統一 Task.FromResult を活用
長時間の処理には不向き Task.Run を使用する
エラーを非同期に伝播 Task.FromException<T> を使う

Task.FromResult<T> を適切に活用することで、パフォーマンスとコードの可読性を向上させることができます。適切な場面で使い分けるようにしましょう!

4
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?