第6章 DIの本体:外から渡す(注入)ってこれ!💉
この章のゴール🎯
この章が終わったら、次の3つができればOKだよ〜😊🌸
- **DI=「必要なものを、外から渡す」**って一言で言える💬💉
- クラスの中の
newを減らして、差し替えできる形にできる🔁✨ - 「
newを完全禁止」じゃなくて、newの置き場所を“外側”へ移す感覚がつかめる📦➡️
まず結論!DIって何?💡

DI(依存性注入)は、ほんとにシンプルで…
「クラスが必要とする部品(依存)を、クラスの外で作って、渡してあげる」 これだけ!💉😊
.NET でも DI はフレームワークの基本機能として整理されていて、IoC を実現する代表的な手段として説明されてるよ📚✨。 (Microsoft Learn)
“よくある失敗”から入ろう😵💫(newが中にある)
例えば、こんな「クラスの中で全部 new する」コード、見覚えあるかも…👀💦
public class ReportService
{
public void Export()
{
var logger = new ConsoleLogger();
var repo = new FileReportRepository("reports");
logger.Log("Export start");
repo.Save("...report data...");
logger.Log("Export done");
}
}
public class ConsoleLogger
{
public void Log(string message) => Console.WriteLine(message);
}
public class FileReportRepository
{
private readonly string _dir;
public FileReportRepository(string dir) => _dir = dir;
public void Save(string data)
{
Directory.CreateDirectory(_dir);
File.WriteAllText(Path.Combine(_dir, "report.txt"), data);
}
}
これの何がつらいの?😭
- 差し替えできない:ログを別の仕組みに変えたい、保存先をDBにしたい…が大変😇
- テストしづらい:
File.WriteAllTextが動いちゃう(テストでファイル作られる)📁💥 - 変更が連鎖しやすい:Exportの中が “全部入り” になって太りがち🍔💦
DI化の手順はこれだけ!3ステップ🍡✨
ここから「外から渡す」形にしていくよ💉😊
✅ ステップ1:依存を“引数で受け取れる形”にする(入口を作る)🚪
まず「差し替え口」を作る(前の章の interface の復習だね🧷)
public interface ILogger
{
void Log(string message);
}
public interface IReportRepository
{
void Save(string data);
}
✅ ステップ2:クラスの中の new をやめて、受け取る(注入)💉
ReportService が **「自分で作る」のをやめて、「渡される」**にするよ✨
public class ReportService
{
private readonly ILogger _logger;
private readonly IReportRepository _repo;
public ReportService(ILogger logger, IReportRepository repo)
{
_logger = logger;
_repo = repo;
}
public void Export()
{
_logger.Log("Export start");
_repo.Save("...report data...");
_logger.Log("Export done");
}
}
ここがDIの核心!😍 **「必要な部品が、コンストラクタ引数に“見えてる”」**のが超大事だよ👀✨ (あとでテストが爆速で楽になる伏線🧪💖)
✅ ステップ3:外側(Program側)で組み立てて渡す📦➡️

「じゃあ誰が作るの?」ってなるよね😊 答えは 外側(アプリ起動側) だよ〜✨
ILogger logger = new ConsoleLogger();
IReportRepository repo = new FileReportRepository("reports");
var service = new ReportService(logger, repo);
service.Export();
これが “手動DI”(DIコンテナ無し)🎉 この章ではまずこれで十分!🫶 (コンテナは後の章で「必要になったら」入れる感じでOK🙆♀️)
「差し替えできる」ってこういうこと🔁✨
例えばログを「何もしない版」に変えたいだけなら…
public class NullLogger : ILogger
{
public void Log(string message) { /* 何もしない */ }
}
組み立て側で差し替えるだけ!
ILogger logger = new NullLogger(); // ←差し替え!
IReportRepository repo = new FileReportRepository("reports");
var service = new ReportService(logger, repo);
service.Export();
ReportServiceの中身は一切変更なしで差し替えできる😍💖 これがDIの気持ちよさだよ〜🎀
ここ大事!「newが悪」じゃないよ😌🍵
DIって「new禁止」じゃなくて、
- ✅ newしていい場所:アプリの外側(組み立て担当)📦
- ⚠️ newを避けたい場所:中心ロジックの中(サービスの中)🍱
っていう 置き場所の話なんだよね😊✨
.NET の世界でも、DIはフレームワークの基本として整理されていて(構成・ログ・Optionsと並ぶ柱みたいな扱い)、中で抱え込まずに外から渡す設計が推されてるよ📚。 (Microsoft Learn)
ミニ演習✍️(手を動かそ〜!)😊💉
演習1:new を探して“外に追い出す”🔎➡️
次のどれが「外に追い出し候補」っぽい?(複数OK)✨
new HttpClient()🌐new SqlConnection()🗄️new DateTime()(現在時刻取得)⏰new Random()🎲new StringBuilder()🧱
ヒント:外部I/O寄り・差し替えたい・テストで困るやつが候補だよ😉
演習2:あなたの過去コードをDIっぽくしてみよう🧰✨
1つ小さめのクラスでいいから、次の手順でやってみてね😊
- 「中で new してる相手」を2つ書き出す📝
- interface を作る🧷
- コンストラクタで受け取る💉
- Program側で組み立てる📦
AI活用(Copilot / Codex)プロンプト例🤖✨
そのまま貼って使える系だよ〜😊🌸
- 「このクラス内で
newしてる依存を列挙して、DI化の手順を提案して」🔎💉 - 「interface 抽出して、コンストラクタ注入にリファクタして。差し替え例もつけて」🧷➡️💉
- 「“組み立て側(Program)”に new を集めた完成形を出して」📦✨
章末チェック✅(これ言えたら勝ち!🎉)
- DIって何?→ **「必要なものを外から渡すこと」**って言える💬💉
ReportServiceの依存はどこで分かる?→ コンストラクタ引数👀newはどこへ移す?→ **外側(組み立て担当)**📦
おまけ:2026年の環境感(超短く)🧁
いまは .NET 10 が LTS で、SDKの最新パッチも 2026-01-13 に出てるよ📅✨。 (Microsoft) さらに .NET 10 のダウンロード情報には C# 14.0 と Visual Studio 2026 のサポートが明記されてるよ〜🛠️✨。 (Microsoft)
次の第7章では、いよいよ IoC(主導権が逆になる) を、今日のコードを使って「なるほど〜!」ってなる形でつなげるよ🌀😊💖