首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Unity 構造函數注入權威指南:從單構造到多構造選擇策略的完整解析

     編輯:關於.NET

Constructor Injection 核心優勢

  • 強依賴聲明:不可變對象、必須依賴的編譯時保證
  • 依賴圖清晰:構造函數參數即依賴清單,無需掃描屬性/方法
  • 封裝性佳:依賴不暴露為公共屬性,防止外部隨意篡改
  • 測試友好:單元測試易於構造測試雙對象傳入

兩大場景與容器決策邏輯

場景一:單一構造函數——自動注入

類僅定義一個構造函數,容器無需任何配置自動解析參數並注入。

public class Mp3Player : IPlayer {
    private readonly Song _song;
    public Mp3Player(Song song, Owner owner) { // 唯一構造函數
        _song = song;
    }
    public void Play() => Console.WriteLine($"Now Playing [{_song.Name}] by ({_song.Singer})");
}
var container = new UnityContainer();
container.RegisterType<IPlayer, Mp3Player>(); // Song、Owner 為具體類自動創建
var player = container.Resolve<IPlayer>();
player.Play(); // 正常輸出
單構造函數輸出
圖 1:單構造函數自動注入成功

場景二:多構造函數——需顯式指定

Unity 提供兩種選擇機制,優先級遞減:

機制 A:[InjectionConstructor] 屬性標記(最高優先級)

public class Mp3Player : IPlayer {
    private readonly Song _song;
    [InjectionConstructor] // 明確指定此構造函數用於 DI
    public Mp3Player(Owner owner) { } // 僅注入 Owner
    public Mp3Player(Song song, Owner owner) { // 完整構造函數,非 DI 入口
        _song = song;
    }
    // ...
}

容器將使用 Mp3Player(Owner) 進行注入,Song 依賴缺失需在其他地方補充。

機制 B:參數最多者勝出(默認回退策略)

public class Mp3Player : IPlayer {
    private readonly Song _song;
    public Mp3Player(Owner owner) { } // 1 參數
    public Mp3Player(Song song, Owner owner) { // 2 參數 → 被選中
        _song = song;
    }
    // ...
}

若無 [InjectionConstructor],容器自動選擇參數最多的構造函數。警告:若存在多個「參數最多」構造函數(參數數量相同),容器拋出異常,必須用 Attribute 明確指定。

關鍵限制與邊界

  • 不支持現有實例:Resolve 獲取現有對象不執行構造函數注入;BuildUp 也不支持(對象已構造)
  • 替代方案:現有實例需注入依賴時,改用屬性注入([Dependency] + BuildUp)
  • 循環引用風險:構造函數參數直接/間接引用自身類型將導致無限遞歸,參考專題文章規避

官方建議與選型決策樹

「如果你不確信要使用哪種注入方式,建議還是使用 Constructor Injection。它更符合幾乎所有的一般需求。」—— Unity 官方文檔

決策流程

  1. 依賴是否為強制/不可變?→ 是 → 構造函數注入
  2. 依賴是否可選/可變/需外部可見?→ 是 → 屬性注入
  3. 初始化邏輯複雜/多步驟/需隱藏依賴?→ 是 → 方法調用注入
  4. 現有實例需補全依賴?→ 屬性/方法注入 + BuildUp

最佳實踐檢查清單

  • [ ] 單構造函數優先,避免多構造歧義
  • [ ] 多構造必加 [InjectionConstructor] 明確意圖
  • [ ] 構造函數參數僅接受抽象/接口,不依賴具體類
  • [ ] 避免構造函數執行耗時/副作用操作(放入初始化方法)
  • [ ] 單元測試驗證容器解析與手動構造雙路徑
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved