2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

簡単に遅延初期化ができるLazy<T>を使ってみた

Last updated at Posted at 2025-08-24

Lazyとは?

C#で遅延初期化をサポートをするための機能です。

主な特徴

  • 初回アクセス時までインスタンス生成を遅延
  • 必要となるまでオブジェクトを生成しないことで、パフォーマンスとメモリ消費の最適化
  • スレッドセーフな遅延初期化

どんなときに使う?

1.アプリ起動時に重い処理や大きなオブジェクト生成を避けたいとき

アプリケーション起動時に大規模なデータ構造や重たい初期化処理を行うと、ユーザビリティの低下につながります。(例えば、大きな配列やデータベース接続、ファイル読み込みなど)

大きいオブジェクトを必要になるときまで初期化を遅延させるために使うことができます。

// メモリ消費量の大きいオブジェクト
public class LargeObject
{
    public readonly List<long> Data = new List<long>();

    public LargeObject()
    {
        for (var i = 0; i < 100_000; i++)
        {
            Data.Add(i);
        }
    }
}

var lazyObject = new Lazy<LargeObject>(() => new LargeObject()); // ここではオブジェクトの生成はされない
Console.WriteLine(lazyObject.Value.Data.Count); // Valueにアクセスして初めて初期化される

2.必要になるまでインスタンス化したくない共通部品やキャッシュ

アプリ全体で使用する共通部品は必ずしも利用されるわけではないですよね。
不要な場面でインスタンス化してしまうと、無駄なメモリやCPUリソースを消費してしまいます。

データが必要になるまでは初期化をせず、情報を保持しておくことができます。

// アプリ共通データを保持するキャッシュクラス
public class Cache
{
    private static readonly Dictionary<int, string> dic = new Dictionary<int, string>
    {
        {1, "One"},
        {2, "Two"},
        {3, "Three"},
    };

    public Lazy<Dictionary<int, string>> cache;

    public Cache()
    {
        this.cache = new Lazy<Dictionary<int, string>>(() => dic);
    }

    public List<string> GetValues()
    {
        // 必要なときだけインスタンス化する
        return cache.Value
            .Select(x => x.Value)
            .ToList();
    }
}

var cache = new Cache();
cache.GetValues().ForEach(x => Console.WriteLine(x)); // 出力: "One", "Two", "Three"

3.DIによるサービスの遅延解決

依存性注入(DI)では、サービスや部品をコンストラクタやプロパティを通じて外部から注入しますが、そのサービスが早いタイミングで使用されるとは限りません。

注入されたタイミングではサービスを解決せず、利用されるときに初めて解決することができます。

// サービスをDIで受け取るクラス
public class Consumer
{
    private readonly Lazy<IMyService> myService;

    public Consumer(Lazy<IMyService> service)
    {
        this.myService = service;
    }

    // このメソッドが呼ばれて初めてIMyServiceが解決される
    public void Execute() => this.myService.Value.DoSomething();
}

// サービスのインターフェース
public interface IMyService
{
    public void DoSomething();
}

注意点

Lazyはオブジェクトの"遅延初期化"をスレッドセーフを保証してくれます。

しかし、生成されたオブジェクトの操作に対してまでスレッドセーフを保証してくれるものではないので注意⚠️

var lazyObj = new Lazy<LargeObject>(() => new LargeObject());
var obj = lazyObj.Value; // Lazy<T>はここまでをスレッドセーフにしてくれる

obj.Data = 123; // ← ここから先はLargeObjectクラス側の責任

参考

2
2
0

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?