什麼情況下使用Property (Setter) Injection
當實例化父對象時也能自動實例化所依賴的對象
通過簡單的方式使得很容易做到在代碼中查看每個類所依賴的項
父對象有很多相互之間有關聯關系的構造器,導致在調試和維護時很不方便。
父對象包含有很多參數構造器,特別是參數類型相似的只能通過參數的位置來辨別的
讓用戶(將調用這些代碼的程序)更方便的看到有哪些對象可以用,這在Constructor Injection裡是沒辦法實現的。
通過修改依賴對象的代碼來控制哪些對象可以被注入,而不用改動父對象或應用程序
准備工作
//歌曲類
public class Song
{
//歌手
public string Singer
{
get
{
return "Westlife";
}
}
//歌曲名
public string Name
{
get
{
return "My Love";
}
}
}
public abstract class Player
{
[Dependency]
public Song Song { get; set; }
public abstract string Name { get; }
public void Play()
{
Console.WriteLine(string.Format("{0}: Now Playing [{1}] Singing by ({2})", this.Name, this.Song.Name, this.Song.Singer));
}
}
public class Mp3Player : Player
{
public override string Name
{
get
{
return "Mp3 Player";
}
}
}
public class CDPlayer : Player
{
public override string Name
{
get
{
return "CD Player";
}
}
}
開始
通過為類的屬性貼上[Dependency]標簽,使得Unity容器在獲取類對象實例時,自動實例化該屬性所依賴的對象,並注入到屬性中。
看一個例子,Mp3Player類有一個Song屬性,它被貼上[Dependency]標簽。
[Dependency]
public Song Song { get; set; }
可以通過下面的方式來獲取Mp3Player對象實例:
IUnityContainer container = new UnityContainer();
container.RegisterType<Player, Mp3Player>();
Player player = container.Resolve<Player>();
player.Play();
看看輸出:
這裡通過為Mp3Player類的Song屬性貼上[Dependency]標簽,來表示Unity容器裝載對象時將自動實例化Song對象,然後注入到Mp3Player的Song屬性裡。
從輸出結果可以看出,容器在裝配Mp3Player對象時自動裝載有加上[Dependency]標簽的所依賴的屬性對象。
還可以為[Dependency]特性指定Name,再看一個例子:
這是一個播放器商店類,為PopularPlayer屬性貼上[Dependency]標簽,同時指定Name為"Mp3Player"。
//播放器商店
在Unity容器中為Player基類注冊兩個映射( Mp3Player 和 CDPlayer ), 分別指定映射的Name。可以通過下面的方式來獲取PlayerStore對象實例,並輸出該店最受歡迎的播放器名:
public class PlayerStore
{
//最受歡迎的播放器類型(Mp3Player、CDPlayer)
[Dependency("Mp3Player")]
public Player PopularPlayer { get; set; }
}
IUnityContainer container = new UnityContainer();
container.RegisterType<Player, Mp3Player>("Mp3Player");
container.RegisterType<Player, CDPlayer>("CDPlayer");
PlayerStore player = container.Resolve<PlayerStore>();
Console.WriteLine(player.PopularPlayer.Name);
輸出:
由於Player映射到Mp3Player和CDPlayer中,通過為[Dependency] Attribute指定Name可以達到匹配對應的具體Player類的目的。
注入到已存在的對象實例
用Resolve方法來獲取已存在的對象實例時不會做PropertyInjection,因為該對象的創建沒受到 Unity 容器的任何影響。可以使用BuildUp方法來強制實現 PropertyInjection。
關於BuildUp方法可參考:
Unity Application Block 1.0系列(5): 使用BuildUp讓已存在對象實例也支持依賴注入
結束語
使用 Property / Setter Injection 需要特別注意不要有循環引用,否則可能會導致應用程序出錯。
關於循環引用可以參考:
Unity Application Block 1.0系列(6): 杜絕循環引用