在分析PRISM項目的時候, 發現里面用到了Unity 這個Component, 主要用於依賴注入的。由於對其不熟悉,索性分析了一下,記載在此,以作備忘。
任何事物的出現,總有它獨特的原因,Unity也是如此。
在Unity產生之前,我們是這么做的
在遠古的時候,當我們需要在一個類A中引用另一個類B的時候,總是將類B的實例放置到類A的構造函數中,以便在初始化類A的時候,得到類B的實例。
public class A { B b; public A() { B = new B(); } }
但是,當項目稍微大一點的時候,維護起來就顯得異常吃力,尤其是當有Code Change的時候,如果類B有了一些修改(比如加入了帶參構造等等),那么這種修改和測試將是異常難受的。
所以,為了解決最原始的問題,我們開始在類A的外部獲取類B的實例,以便能夠減輕依賴:
public class A { B b; public A(B _b) { This.b = _b; } }
這樣,只需要在外部實例化B,然后傳入類A即可。這樣做,雖然比原始做法方便了許多,然是在類A內部,依然存在着對類B的依賴。由於類B在系統中是唯一的,所以說當有許多個類似於類B的對象需要進行初始化的時候,這種工作量…誰能夠想象呢?
有了問題,才會思考變化,於是接口開始在這方面體現他的威力了:
public class A { IMyObject myObj; public A(IMyObject myObj) { this.myObj = myObj; } }
將相似的操作抽出來,放入接口中。現在,你就擁有了許多可以操縱的類對象(繼承了IService接口的類)。並且采用接口以后,你可以更加容易的進行開發和測試,並且維護起來也相對簡單。比如,如果你想測試接口中的DataExtracting功能,那么你完全可以寫一個類繼承自這個接口,只實現DataExtracting功能即可,簡單,方便。
在Unity產生之后,我們是這么做的
現在,Unity將這種操作更加的簡單化,我們可以理解為這樣,Unity將繼承了接口的類進行了橫切,然后提供了還原的方法:
進行依賴注入:
UnityContainer container = new UnityContainer(); private void button1_Click(object sender, EventArgs e) { container.RegisterType<IMyObject, MyObjectFirstImplementation>(DependencyRegistrationKeys.FirstImplementation); container.RegisterType<IMyObject, MyObjectSecondImplementation>(DependencyRegistrationKeys.SecondImplementation); container.RegisterType<IMyObject, MyObjectThirdImplementation>(); container.RegisterType<IMyObject, MyObjectFirstImplementation>(); }
還原實體類:
public MyObjectFactory(UnityContainer unityContainer) { this.unityContainer = unityContainer; } public UnityContainer unityContainer; public IMyObject Create(string objKey) { return unityContainer.Resolve<IMyObject>(objKey); }
最后給出一個例子作為參考,這個例子主要是講解Unity如何進行注冊對象以及還原的:
實例說明
首先,我們需要有一個IMyObject接口,然后有三個類繼承自此對象:
接口:

namespace UnityDaemon { public interface IMyObject { string DoSomething(); } }
MyObjectFirstImplementation類:

namespace UnityDaemon { public class MyObjectFirstImplementation:IMyObject { public string DoSomething() { return "You call me ? I am the first one, I am from MyObjectFirstImplementation!! "; } } }
MyObjectSecondImplementation類:

namespace UnityDaemon { public class MyObjectSecondImplementation:IMyObject { public string DoSomething() { return "You call me ? I am the second one, I am from MyObjectSecondImplementation!! "; } } }
MyObjectThirdImplementation類:

namespace UnityDaemon { public class MyObjectThirdImplementation:IMyObject { public string DoSomething() { return "I am the third. Do whatever you want to ~~~"; } } }
當然,這里我們還可以增加更多的類...
然后,我們需要創建一個Factory,用於根據Object名稱來還原對象:

using Microsoft.Practices.Unity; namespace UnityDaemon { public class MyObjectFactory { public MyObjectFactory() { } public MyObjectFactory(UnityContainer unityContainer) { this.unityContainer = unityContainer; } public UnityContainer unityContainer; public IMyObject Create(string objKey) { return unityContainer.Resolve<IMyObject>(objKey); } } }
這樣做完之后,我們就可以來使用了,我利用Winform做的界面,Button1用來注冊類型,Button2用來還原有名稱的對象,Button3用來還原無名稱的對象:

using System; using System.Windows.Forms; using Microsoft.Practices.Unity; namespace UnityDaemon { public partial class MainFrm : Form { UnityContainer container; public MainFrm() { InitializeComponent(); container = new UnityContainer(); } private void button1_Click(object sender, EventArgs e) { container.RegisterType<IMyObject, MyObjectFirstImplementation>(DependencyRegistrationKeys.FirstImplementation); container.RegisterType<IMyObject, MyObjectSecondImplementation>(DependencyRegistrationKeys.SecondImplementation); container.RegisterType<IMyObject, MyObjectThirdImplementation>(); container.RegisterType<IMyObject, MyObjectFirstImplementation>(); } private void button2_Click(object sender, EventArgs e) { var factory = new MyObjectFactory(container); var myObj = factory.Create(DependencyRegistrationKeys.FirstImplementation); string str = myObj.DoSomething(); MessageBox.Show(str); var myObj1 = factory.Create(DependencyRegistrationKeys.SecondImplementation); string str1 = myObj1.DoSomething(); MessageBox.Show(str1); } private void button3_Click(object sender, EventArgs e) { var myObj1 = container.Resolve<IMyObject>(); MessageBox.Show(myObj1.DoSomething()); } } }
這樣,當我們運行起來,先點擊Button1的時候,三個類都被注冊進了容器中。當點擊Button2的時候,顯示出來的結果和預想一樣。當點擊Button3的時候,僅僅顯示了
You call me ? I am the first one, I am from MyObjectFirstImplementation!!
原因是什么呢? 原因就在於當注冊的時候,沒有提供名稱的話,那么解析的時候,則以最后一次注冊的為准。所以這也是MyObjectThirdImplementation類中的函數沒有被執行的原因。
源碼下載
參考連接
http://stackoverflow.com/questions/4612054/wpf-prism-what-is-a-unity-container
http://blogsprajeesh.blogspot.hk/search/label/PRISM