Unity 同時支持三種注入模式,且每種均提供Attribute 標記(侵入式)與XML 配置(非侵入式)雙重實現路徑,滿足不同架構潔癖度需求。
public interface IDialer { void Dial(string number); }
public abstract class Dialer : IDialer { public abstract void Dial(string number); }
public class ButtonDialer : Dialer { public override void Dial(string n) => Console.WriteLine("Button: " + n); }
public class PlateDialer : Dialer { public override void Dial(string n) => Console.WriteLine("Plate: " + n); }
public class Telephone {
public Dialer Dialer { get; set; } // 屬性注入目標
public Telephone(IDialer dialer) { } // 構造函數注入目標
public void Init(IDialer dialer) { } // 方法注入目標
}
Telephone 僅有一個 Telephone(IDialer) 時,容器自動解析 IDialer 映射並注入,無需任何標記或配置。
新增 Telephone(string) 後,容器無法決策,拋 ResolutionFailedException。兩種指定方式:
public class Telephone {
[InjectionConstructor]
public Telephone(IDialer dialer) { } // 標記此構造函數用於 DI
public Telephone(string dummy) { }
}
客戶端代碼需載入配置:
var container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Configure(container);
public class Telephone {
[Dependency]
public Dialer Dialer { get; set; } // 標記需注入,類型為抽象類 Dialer
// ...
}
容器同時應用構造函數注入(先)與屬性注入(後),最終屬性值生效。
propertyType 對應屬性聲明類型,區別於構造函數的 parameterType。
public class Telephone {
[InjectionMethod]
public void Initialize(IDialer dialer) { /* 初始化邏輯 */ }
}
結構與構造函數注入配置幾乎相同,差別在於 method name 指定目標方法。
| 維度 | Attribute 標記 | XML 配置 |
|---|---|---|
| 侵入性 | 侵入領域模型(引用 Unity 程序集) | 零侵入,純 POCO |
| 可讀性 | 代碼即文檔,IDE 導航友好 | 集中管理,適合運維/部署階段調整 |
| 重構安全 | 重構工具自動更新標記 | 字符串易出錯,需測試保護 |
| 適用階段 | 開發期、核心領域模型穩定 | 部署期、多環境差異化配置 |
最佳實踐:核心領域用 Attribute,部署差異用配置覆蓋,兩者可共存(配置優先級更高)。