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