MS_IoCAOPDI - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
フレームワークやクラスライブラリなどの開発に必要になる知識。
補足(本ページの読み方): タイトルの矢印は
**「上位の目的 → それを実現する技術」**という向きを表している。【何をしたいか(目的・原則)】 【どう実現するか(技術)】 共通化技法 ├─ IoC(コードの中で解決) ──┐ └─ AOP(コードの外で解決) ──┤ ├──→ DI(依存性の注入) 依存性反転原則(差し替え) ─────┘つまり、
- IoC / AOP / 依存性反転原則は「考え方」、
- DI はそれらを実装する「手段」、
という関係である。
名前が似ていて混同されやすいが、層が違うという点が本ページの主旨。
上記の共通化技法(IoC、AOP)、
依存性反転原則で使用される技術。
各メソッド内に別のメソッドを呼び出す「処理の共通的パターン」がある場合、
オブジェクト指向ではこれを共通化できず、処理が散在してしまう問題に対するソリューション。
補足(「散在してしまう問題」とは): 具体例で言うと、
ロギング・トランザクション・認可・計測などが典型である。public void 注文する(Order o) { _log.Info("注文する 開始"); // ← ロギング(散在する) using var tx = BeginTransaction(); // ← トランザクション(散在する) try { /* ここだけが本来の関心事 */ tx.Commit(); } catch { tx.Rollback(); throw; } _log.Info("注文する 終了"); // ← ロギング(散在する) }こうした**「本来の関心事に対して横断的に現れる関心事」**を
**横断的関心事(cross-cutting concern)**と呼ぶ。オブジェクト指向の継承・委譲では、
「メソッドの前後に処理を挟む」という形の共通化ができない
(継承は「置き換え」であって「挟み込み」ではない)。
ここが IoC / AOP の出発点である。
コードの中で上記の解決を実現する。
コードの外で上記の解決を実現する。
補足(「中」と「外」の対比): 原文の要約は的確なので、
具体化して補っておく。
IoC(コードの中) AOP(コードの外) やり方 フレームワーク側が呼ぶ構造にする ウィービングで後から織り込む 例 テンプレート メソッド、コールバック、DI 属性、プロキシ、IL 書き換え 共通処理の場所 基底クラス/フレームワーク側 別モジュール(アスペクト) 呼び出し側の記述 明示的に見える 見えない(=追いにくい) // IoC 的(テンプレート メソッド):構造はコードに現れている public sealed class 注文サービス : TransactionalService { protected override void Execute(Order o) { /* 本来の関心事だけ */ } } // AOP 的:属性だけ付ける。ログもトランザクションもコードに現れない [Logging, Transactional] public void 注文する(Order o) { /* 本来の関心事だけ */ }AOP の方が記述量は減るが、
**「コードを読んでも何が起きるか分からない」**という代償がある。
AOP の末尾で原文が「不評ですね」と書いているのは、
この点が実務で嫌われたためである。
ライブラリの差し替え技法として使用される。
実現する技術の名称をそのまま使用して、単に、DIと呼ばれることも多い。
補足(用語の混同を整理する): 原文が指摘する通り、
現場ではすべて「DI」と呼ばれてしまうことが多い。
正確には次の 3 つは別物である。
略語 正式名称 何を指すか IoC Inversion of Control 制御の流れが反転しているという構造の特徴 DIP Dependency Inversion Principle(依存性反転原則) 上位が下位に依存しないという設計原則(SOLID の D) DI Dependency Injection(依存性の注入) 外から依存オブジェクトを渡すという実装技法 **DIP は「何を目指すか」、DI は「どうやるか」**である。
DI を使わずに DIP を満たすこともできるし
(引数で渡す、ファクトリを使う等)、
DI を使っていても DIP を満たしていない設計もあり得る
(具象クラスを注入している場合など)。【DIP を満たしていない】 【DIP を満たす】 業務ロジック 業務ロジック │ 依存 │ 依存 ↓ ↓ SqlServerRepository IRepository(抽象) ↑ 実装 SqlServerRepository = 上位が下位の具象に依存 = 上下とも抽象に依存し、 矢印が「反転」している「反転」という語は、依存の矢印の向きが反転することを指す。
補足(現在の実務では意識せず使っている): これらの概念は、
現在の .NET ではフレームワークに組み込まれているため、
名前を意識せずに使っている場合が多い。// Program.cs:これが DI コンテナーへの登録(DIP を前提とした設計) builder.Services.AddScoped<IOrderRepository, SqlOrderRepository>(); // 利用側:コンストラクタで抽象だけを受け取る(constructor 注入) public sealed class OrderService(IOrderRepository repo) { ... }詳細は .NET Core における DI /
ASP.NET Core における DI を参照。
- .NET での依存関係の挿入
https://learn.microsoft.com/ja-jp/dotnet/core/extensions/dependency-injection - 依存関係逆転の原則(アーキテクチャ ガイド)
https://learn.microsoft.com/ja-jp/dotnet/architecture/modern-web-apps-azure/architectural-principles#dependency-inversion
Tags: 移行, プログラミング, .NET開発