類別、元件和控制項的比較
更新:2007 年 11 月
這個主題將定義元件和控制項;這裡的討論應可協助您決定何時應實作元件或控制項的類別。
下列清單為實作人員提供了較廣泛的方針。
如果您的類別使用外部資源,但是不會用在設計介面上,請實作 System.IDisposable,或是從直接或間接實作 IDisposable 的類別衍生。
如果您的類別會用在設計介面上 (例如 Windows Form 或 Web Form 設計工具),請實作 System.ComponentModel.IComponent,或是從直接或間接實作 IComponent 的類別衍生。請注意,IComponent 會擴充 IDisposable,因此 IComponent 型別一定是 IDisposable 型別。IComponent 型別在效能上的負荷比非 IComponent 的 IDisposable 型別要大,但是這個劣勢通常因為這個型別可以在設計階段和執行階段設置 IComponent 而抵銷 (設置會在這個主題稍後加以說明)。
如果您需要可以設計的類別 (用在設計介面上) 而且可用傳址 (By Reference) 方式封送處理,您可以從 System.ComponentModel.Component 衍生。Component 是用傳址方式封送處理的 IComponent 型別的基底實作。
如果您需要可以設計的類別而且可用傳值 (By Value) 方式封送處理,您可以從 System.ComponentModel.MarshalByValueComponent 衍生。MarshalByValueComponent 是用傳值方式封送處理的 IComponent 型別的基底實作。
如果您想引入物件模型階層架構中的 IComponent 型別 (而且由於單一繼承的關係而無法從 Component 或 MarshalByValueComponent 這類基底實作衍生),請實作 IComponent。
如果您想要一個可以提供使用者介面的可設計類別,那麼您的類別就是控制項。控制項必須直接或間接衍生自下列其中一個基底控制項類別:System.Windows.Forms.Control 或 System.Web.UI.Control。
注意事項: 如果類別不可設計,也沒有保留外部資源,您就不需要 IComponent 或 IDisposable 型別。
接著說明的是元件、控制項、容器和站台的定義。
元件
在 .NET Framework 中,元件是實作 System.ComponentModel.IComponent 介面的類別,或是從實作 IComponent 之類別直接或間接衍生的類別。在程式設計中,元件一詞通常是使用於可以重複使用而且可以與其他物件互動的物件。.NET Framework 元件不僅滿足這些一般性的要求,並且還額外地提供一些功能,例如對外部資源的控制以及設計階段支援。
對外部資源的控制
IComponent 介面擴充 IDisposable 介面,在這個介面的合約中有一個名為 Dispose 的方法。在它的 Dispose 方法實作中,元件必須明確地釋放外部資源。這樣就提供一種釋放資源的決定性方式,不同於透過記憶體清除發生的預設非決定性清除。開發者必須傳播 Dispose 到整個內含項目階層架構,以確保元件的子系也會釋放資源。此外,衍生的元件必須叫用其基底類別的 Dispose 方法。
注意事項: |
---|
即使透過 Dispose 提供對資源的明確控制,您仍然應該透過完成項 (解構函式) 提供隱含的清除,以防止使用者萬一沒有對元件呼叫 Dispose 時,造成資源的永久性遺漏。 |
下列範例所示是在基底元件和衍生元件中實作 Dispose 的模式。
public class BaseComponent : IComponent {
// IComponent extends IDisposable.
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
// Free other state (managed objects).
}
// Free your own state (unmanaged objects).
}
// Simply call Dispose(false).
~BaseComponent(){
Dispose (false);
}
}
// Derived component.
public class DerivedComponent : BaseComponent {
protected override void Dispose(bool disposing) {
if (disposing) {
// Free other state.
}
// You must invoke the Dispose method of the base class.
base.Dispose(disposing);
// Free your own state.
...
}
// No finalizer/destructor.
// No Dispose() method.
}
' Design pattern for a base class.
Public Class BaseComponent
Implements IComponent
' Implement IDisposable
Public Overloads Sub Dispose()
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overloads Overridable Sub Dispose(disposing As Boolean)
If disposing Then
' Free other state (managed objects).
End If
' Free your own state (unmanaged objects).
' Set large fields to null.
End Sub
Protected Overrides Sub Finalize()
' Simply call Dispose(False).
Dispose (False)
End Sub
End Class
' Design pattern for a derived component.
Public Class DerivedComponent
Inherits BaseComponent
Protected Overloads Overrides Sub Dispose(disposing As Boolean)
If disposing Then
' Release managed resources.
End If
' Release unmanaged resources.
' Set large fields to null.
' Call Dispose on your base class.
Mybase.Dispose(disposing)
End Sub
' The derived class does not have a Finalize method
' or a Dispose method with parameters because it inherits
' them from the base class.
End Class
設計階段支援
.NET Framework 中的元件有一個重要功能,那就是它們是可設計的,這表示身為元件的類別可用於快速應用程式開發 (RAD) 環境中,例如 Visual Studio。您可以將元件加入至 Visual Studio 的工具箱、可將其拖放到表單上,也可以在設計介面上進行操作。請注意,IComponent 型別的基底設計階段支援是內建於 .NET Framework;元件開發人員不必執行額外的工作,就可以使用基底設計階段的功能。
如需設計階段支援的詳細資訊,請參閱元件的設計階段屬性和擴充設計階段支援。
裝載元件
元件可以設置 (裝載) 於容器內 (本主題稍後會再詳加說明)。當元件被設置時,它是透過它的站台 (本主題稍後會再詳加說明) 與容器互動,並且能夠透過站台從它的容器查詢和取得服務。為確保容器被拆除時資源會被釋放,容器必須實作 IDisposable 介面。容器在它的 Dispose 方法實作中,必須釋放它所持有的所有資源,並且叫用它所包含每一個元件的 Dispose 方法。
內含項目是邏輯性的,不需要具有視覺化的表示方式。設置資料庫元件的中介層 (Middle Tier) 容器就是非視覺化內含項目的範例。視覺化的內含項目會顯示在 Visual Studio 的 Windows Form 設計工具和 Web Form 設計工具中。視覺化的設計介面是一個容器,可裝載表單元件 (在 Web Form 中是 Page 元件)。
封送處理元件
元件可分為可遠端處理者及不可遠端處理者。可遠端處理的元件是以傳址 (By Reference) 或傳值 (By Value) 方式封送處理。封送處理包括跨界限傳送物件,所謂界限包括應用程式定義域 (輕量處理序)、處理序和電腦。當物件以傳址方式封送處理時,會建立對該物件進行遠端呼叫的 Proxy。當物件以傳值方式封送處理時,會跨相關界限傳送物件的序列化複本。
封裝系統資源、大型或以單一執行個體存在的可遠端處理元件應該以傳址方式封送處理。用傳址方式封送處理的元件基底類別是 System.ComponentModel.Component。這個基底類別會實作 IComponent 並且從 MarshalByRefObject 衍生。.NET Framework 類別庫中的許多元件都是從 Component 衍生而來,包括 System.Windows.Forms.Control (Windows Form 控制項的基底類別)、System.Web.Services.WebService (使用 ASP.NET 所建立的 XML Web Service 的基底類別) 和 System.Timers.Timer (產生遞迴事件的類別)。
只存有狀態的可遠端處理元件應該以傳值方式封送處理。用傳值方式封送處理的元件基底類別是 System.ComponentModel.MarshalByValueComponent。這個基底類別會實作 IComponent 並且從 Object 衍生。.NET Framework 中只有少數幾個元件是從 MarshalByValueComponent 衍生。這類元件都位於 System.Data 命名空間 (DataColumn、DataSet、DataTable、DataView 和 DataViewManager)。
注意事項: |
---|
以傳值和傳址方式封送處理之物件的基底類別分別為 Object 和 MarshalByRefObject,但是對應的衍生類別則命名為 MarshalByValueComponent 和 Component。這種命名配置所依據的邏輯是,越常使用的型別要具有越簡單的名稱。 |
如果元件不需要遠端處理,就不要從 Component 的基底實作衍生,而是直接實作 IComponent。
如需物件遠端處理的詳細資訊,請參閱 .NET 遠端處理概觀。
控制項
控制項是一種提供 (或啟用) 使用者介面 (UI) 能力的元件。.NET Framework 為控制項提供了兩個基底類別:一個是用戶端 Windows Form 控制項,另一個是 ASP.NET 伺服器控制項。這些是 System.Windows.Forms.Control 和 System.Web.UI.Control。.NET Framework 類別庫中的所有控制項都是從這兩個類別直接或間接衍生。System.Windows.Forms.Control 是衍生自 Component 而且本身提供 UI 功能。System.Web.UI.Control 會實作 IComponent,而且會提供很容易在上面加入 UI 功能的基礎結構。
注意事項: |
---|
每個控制項都是一個元件,但每個元件不一定是控制項。 |
容器和站台
如果您要開發 Windows Form 或 Web Form 網頁 (ASP.NET 網頁) 的元件和控制項,您不需實作容器或站台。Windows Form 和 Web Form 的設計工具,就相當於 Windows Form 和 ASP.NET 伺服器控制項的容器。容器可對設置於它們之內的元件和控制項提供服務。在設計階段,控制項是設置在設計工具中,並且從設計工具取得服務。為完整起見,僅將容器和站台的定義列述如下。
Container
容器是實作 System.ComponentModel.IContainer 介面的類別,或者從實作這個介面之類別衍生的類別。容器在邏輯上可包含一個或多個被稱為容器子元件的元件。Site
站台是實作 System.ComponentModel.ISite 介面的類別,或者從實作這個介面之類別衍生的類別。站台是由容器提供,用來管理其子元件並且與它們通訊。通常,一個容器和一個站台會實作為一個單元。