依存性注入ってなんですか先輩? 〜Microsoft.Extensions.DependencyInjectionで学ぶDIの基本〜

2025年4月24日木曜日

AIに聞いてみた C#

ChatGPTにDI(依存性注入)について聞いてみました。

タイトル、文章、イラスト: ChatGPT

登場人物

  • ミナト(左): IT企業に入社したばかりの新人。C#歴半年。最近「DI」という単語にビビってる。
  • ハルカ(右): 先輩エンジニア。業務で.NETを使い倒している。説明はわかりやすいと社内で評判。

1. 「DIって……何者ですか?」

ミナト「先輩! 最近プロジェクトのコードにAddTransientとかAddSingletonとか出てくるんですけど……それ何ですか?」

ハルカ「ああ、それは依存性注入(Dependency Injection)ってやつだね」

ミナト「あ、噂のDI! ……でも、なんでそんなことするんですか?」

ハルカ「じゃあ、ちょっと例で説明してみようか!」

2. 依存性って、そもそも何?

ハルカ「たとえば、アプリの中であいさつメッセージを出すクラスがあるとするよ」

C#:

  1. public class GreetingService
  2. {
  3. public void Greet() => Console.WriteLine("こんにちは!");
  4. }

ハルカ「これを別のクラスで使うとしたら、普通はこうやって書くよね」

C#:

  1. public class MyApp
  2. {
  3. private GreetingService _greeting = new GreetingService();
  4.  
  5. public void Run() => _greeting.Greet();
  6. }

ミナト「あ、見慣れたnewのやつですね」

ハルカ「うん。でもこれって、MyAppGreetingServiceにガッツリ依存してるってことなんだ」

3. 依存性注入って何がうれしいの?

ハルカ「もしGreetingServiceをテスト用に差し替えたかったら……とか、複数の実装を切り替えたかったら……この書き方だと柔軟性がないんだよね」

ミナト「あ~、確かに毎回newしてたら変更もしづらそう……」

ハルカ「そこで! GreetingServiceを外から渡してあげる。これが依存性を注入するってこと」

C#:

  1. public class MyApp
  2. {
  3. private readonly IGreetingService _greeting;
  4.  
  5. public MyApp(IGreetingService greeting)
  6. {
  7. _greeting = greeting;
  8. }
  9.  
  10. public void Run() => _greeting.Greet();
  11. }

ミナト「なるほど……でも、どうやって渡すんですか?」

ハルカ「そこを助けてくれるのがMicrosoft.Extensions.DependencyInjectionなんだ!」

4. 実際にDIコンテナに登録してみよう

C#:

  1. var services = new ServiceCollection();
  2. services.AddTransient<IGreetingService, GreetingService>();
  3. services.AddTransient<MyApp>();
  4.  
  5. var provider = services.BuildServiceProvider();
  6. var app = provider.GetRequiredService<MyApp>();
  7. app.Run();

ミナト「うおっ! MyAppを取得するだけで、内部のGreetingServiceも自動で用意されてる!」

ハルカ「それがDIのすごいところ。使う側は依存するものを知らなくていい。全部DIコンテナがつないでくれる」

5. AddTransient/AddSingleton/AddScopedの違い

ハルカ「あと、サービスのライフサイクルも選べるよ」

登録方法 インスタンス生成タイミング
AddTransient 毎回新しく
AddScoped リクエストごと(Web用)
AddSingleton アプリ起動からずっと同じ

ミナト「なるほど、用途によって使い分けるんですね」

ハルカ「うん、特にWebアプリではAddScopedがよく使われるかな」

まとめ: DIはコードの見通しを良くしてくれる

ハルカ「DIは、クラス間の依存を外から注入して、テストしやすく、交換しやすくしてくれる仕組み」

ミナト「最初は魔法みたいだけど、仕組みがわかるとすごく納得です!」

ハルカ「これがわかると、今後Hostの中でConfigureServicesを見るたびに、『あ、あれDIの登録だ!』ってなるよ~」

ミナト「もうAddTransientが怖くないです!」

参照