我們經常看見許多.NET的Class是從System.ComponentModel.Component繼承過來的,他實現了System.ComponentModel.IComponent介面,而且MS也在Visual Studio .NET中,推薦你經常使用System.ComponentModel.Component作為基礎類。但是很遺憾,很多人不知道為什麼這樣做。
MS的解釋包括:
1、控制外部資源
IComponent 介面繼承自 System.IDisposable 介面,這樣可以控制對象的釋放。
2、設計時支援
只要是支援IComponent介面,都可以看見一個設計器,並且拖入到這個組件中的子組件都會自動產生以下代碼: this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components);
以便加入網站。
3、承載組件
所有的子組件都是通過 IContainer 管理的,所以你的子組件都是被管理的。
事實上,很多人看見這些特性還是雲裡霧裡,對於ISite、IContainer和IComponment的關係還是難以理解,那麼我們看看這個圖形。
通過這個圖,我想理解應該好一些吧。
討論:
1、IComponent使用了注入依賴的思想;
我發現IComponent的Site屬性是Get 和Set的,也就是說,IComponent實現需要有人初始化Site才能正常工作,不信的話你直接執行個體化一個Component對象,訪問Site你會發現是Null的。
Visual Studio .NET的設計器在執行個體化一個IComponent對象時,會自動產生如下的代碼:
this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components);
這段代碼實際上就是協助你的errorProvider1對象初始化Site屬性。
另外,ISite繼承了System.IServiceProvider,所以也對應的注入了服務的提供者。
關於注入依賴,請參考尋找AOP和Ioc
2、.NET 2.0 增加了INestedContainer
容器一般來說,也是被另外一個IComponent持有,你也許注意到我們的設計器總是會產生這樣的代碼: private System.ComponentModel.IContainer components = null;
但是這個容器物件,我們發現他並不包含 Owner 的引用,也就是說,你的子物件可以互相通訊,但是你的子物件不能訪問到 他的父。
基於以上問題,.NET 2.0中增加了INestedContainer介面(繼承自IContainer),他新增了Owner屬性,可以訪問到容器所在的所有者,即父。
3、IComponent適合的範圍
我注意到,自動產生的程式碼中,這個組件公用一個容器,也就是說,只有整個組件釋放,容器才會釋放。所以當你使用一個組件時,請及時的釋放這個對象。
如果你打算設計無狀態的服務類,請不要使用設計器,而是需要某個子組件時,才建立,並使用容器統一管理,諸如以下的代碼: public void Save() {
//使用容器統一管理資源。
using (Container container = new Container()) {
Component1 c1 = new Component1(container);
c1.Do();
Component2 c2 = new Component2(container);
c2.Do();
}
}