类、组件和控件
本主题对组件和控件进行了定义;此处进行的讨论可以帮助您决定何时实现一个是组件或控件的类。
备注
本主题介绍 Windows 窗体和 ASP.NET 类。此处进行的讨论不适用于 WPF 类。有关创作 WPF 控件的信息,请参见控件创作概述。
以下列表为实施者提供了全面的指南。
如果您的类使用外部资源但不用于设计图面,则实现 IDisposable,或者从直接或间接实现 IDisposable 的类派生。
如果您的类要用于设计图面(如 Windows 窗体或 Web 窗体设计器)上,则实现 IComponent,或者从直接或间接实现 IComponent 的类派生。 请注意,IComponent 扩展 IDisposable,因此 IComponent 类型始终是 IDisposable 类型。 与不是 IComponent 的 IDisposable 类型相比,IComponent 类型的性能系统开销要小。但这一不足通常可由在设计时和运行时安置 IComponent 的能力来弥补。 (在本主题的后面部分将对该安置功能进行说明)。
如果您需要一个可设计(可在设计图面上使用)并且可按引用封送的类,则可从 Component 派生。 Component 是按引用封送的 IComponent 类型的基实现。
如果您需要一个可按值封送的可设计类,则可从 MarshalByValueComponent 派生。 MarshalByValueComponent 是按值封送的 IComponent 类型的基实现。
如果希望向对象模型层次中引入 IComponent 类型,但由于单次继承的原因而不能从 Component 或 MarshalByValueComponent 之类的基派生,请实现 IComponent。
如果需要提供用户界面的可设计类,则该类是控件。 控件必须从以下基本控件类之一直接或间接派生:Control 或 Control。
备注
如果您的类既不是可设计类,也不保存外部资源,则不需要 IComponent 或 IDisposable 类型。
下面是组件、控件、容器和站点的定义。
组件
在 .NET Framework 中,组件是一种类,它实现 IComponent 接口或者直接或间接地从实现 IComponent 的类派生。 在编程中,“组件”这个术语通常用于可重复使用并且可以和其他对象进行交互的对象。 .NET Framework 组件满足这些一般要求,另外还提供诸如控制外部资源和设计时支持等功能。
控制外部资源
IComponent 接口扩展 IDisposable 接口,后者在其协定中有一个名为 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 方法。
包容是逻辑上的,不需要可视的表示形式。 放置数据库组件的中间层容器就是非可视包容的一个示例。 可在 Visual Studio 的 Windows 窗体设计器和 Web 窗体设计器中找到可视包容。 可视化设计图面是承载窗体组件(Web 窗体中的页组件)的容器。
封送组件
组件可以是可远程控制的或不可远程控制的。 可远程控制的组件由引用或值进行封送。 封送操作涉及跨边界发送对象,这些边界包括应用程序域(轻量进程)、进程甚至计算机,等等。 当对象由引用封送时,会创建一个代理对该对象进行远程调用。 当对象由值进行封送时,跨相关边界发送该对象的一个序列化的副本。
以下可远程控制的组件应该由引用封送:封装系统资源的可远程控制组件,较大的可远程控制组件或作为单个实例存在的可远程控制组件。 按引用封送的组件的基类是 Component。 该基类实现 IComponent 并从 MarshalByRefObject 派生。 .NET Framework 类库中的许多组件从 Component 派生,包括 Control(Windows 窗体控件的基类)、WebService(使用 ASP.NET 创建的 XML Web services 的基类)和 Timer(生成递归事件的类)。
仅保留状态的可远程控制组件应该由值封送。 按值封送的组件的基类是 MarshalByValueComponent。 该基类实现 IComponent 并从 Object 派生。 .NET Framework 类库中只有少量组件从 MarshalByValueComponent 派生。 所有此类组件都在 System.Data 命名空间中(DataColumn、DataSet、DataTable、DataView 和 DataViewManager)。
备注
按值和按引用封送的对象的基类分别是 Object 和 MarshalByRefObject,但对应的派生类名为 MarshalByValueComponent 和 Component。命名方案背后的逻辑是越常用的类型,其名称就越简单。
如果不对组件进行远程控制,则不要从 Component 的基实现派生,而应直接实现 IComponent。
控件
控件是提供(或实现)用户界面 (UI) 功能的组件。 .NET Framework 为控件提供两个基类:一个用于客户端 Windows 窗体控件,另一个用于 ASP.NET 服务器控件。 它们是 Control 和 Control。 .NET Framework 类库中的所有控件都直接或间接从这两个类派生。 Control 从 Component 派生,本身提供 UI 功能。 Control 实现 IComponent,并提供可在其上轻松添加 UI 功能的基础结构。
备注
每个控件都是一个组件,但并不是每个组件都是控件。
容器和站点
如果您正在为 Windows 窗体或 Web 窗体页(ASP.NET 页)开发组件和控件,则不需要实现容器或站点。 Windows 窗体和 Web 窗体的设计器就是 Windows 窗体和 ASP.NET 服务器控件的容器。 容器向放置在其中的组件和控件提供服务。 在设计时,控件放置在设计器中并从设计器获得服务。 为了保持完整性,以下给出了容器和站点的定义。
Container
容器是一个实现 IContainer 接口的类,或从实现该接口的类派生的类。 容器在逻辑上包含一个或多个组件,这些组件叫做容器的子组件。Site
站点是一个实现 ISite 接口的类,或从实现该接口的类派生的类。 站点由容器提供,用来管理其子组件及与子组件进行通信。 通常,容器和站点作为一个单元来实现。
请参见
概念
其他资源
使用 .NET Framework 开发自定义 Windows 窗体控件