Class vs. Component vs. Control

This topic defines component and control; the discussion presented here should help you decide when to implement a class that is a component or a control.

The following list provides broad guidelines for implementers.

  • If your class uses external resources but will not be used on a design surface, implement System.IDisposable, or derive from a class that directly or indirectly implements IDisposable.

  • If your class will be used on a design surface (such as the Windows Forms or Web Forms designer), implement System.ComponentModel.IComponent, or derive from a class that directly or indirectly implements IComponent. Note that IComponent extends IDisposable, so an IComponent type is always an IDisposable type. An IComponent type has a small performance overhead over an IDisposable type that is not an IComponent, but this is generally offset by the ability to site an IComponent at design time and at run time. (Siting is explained later in this topic.)

  • If you want a class that is designable (used on a design surface) and is marshaled by reference, you can derive from System.ComponentModel.Component. Component is the base implementation of an IComponent type that is marshaled by reference.

  • If you want a designable class that is marshaled by value, you can derive from System.ComponentModel.MarshalByValueComponent. MarshalByValueComponent is the base implementation of an IComponent type that is marshaled by value.

  • If you want to introduce an IComponent type in your object model hierarchy and cannot derive from a base implementation such as Component or MarshalByValueComponent due to single inheritance, implement IComponent.

  • If you want a designable class that provides a user interface, your class is a control. A control must derive directly or indirectly from one of the base control classes — System.Windows.Forms.Control or System.Web.UI.Control.

    Note   If your class is neither designable nor holds external resources, you do not need an IComponent or an IDisposable type.

Definitions of component, control, container, and site follow.

Component

In the .NET Framework, a component is a class that implements the System.ComponentModel.IComponent interface or that derives directly or indirectly from a class that implements IComponent. In programming, the term component is generally used for an object that is reusable and can interact with other objects. A .NET Framework component satisfies those general requirements and additionally provides features such as control over external resources and design-time support.

Control over external resources

The IComponent interface extends the System.IDisposable interface, which has a method named Dispose in its contract. In its implementation of the Dispose method, a component must release external resources explicitly. This provides a deterministic way to free resources, in contrast to the default nondeterministic cleanup that happens through garbage collection. Developers must propagate Dispose throughout a containment hierarchy to ensure that children of a component also free resources. Additionally, a derived component must invoke the Dispose method of its base class.

Note   Even when you provide explicit control over resources through Dispose, you should always provide implicit cleanup through the finalizer (destructor) to prevent resources from permanently leaking if a user fails to call Dispose on your component.

The following example shows the pattern for implementing Dispose in a base component and in a derived component.

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.
}

   
[Visual Basic]' 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

Design-Time Support

An important feature of components in the .NET Framework is that they are designable, which means that a class that is a component can be used in a rapid application development (RAD) environment such as Visual Studio .NET. A component can be added to the toolbox of Visual Studio .NET, can be dragged and dropped onto a form, and can be manipulated on a design surface. Note that base design-time support for IComponent types is built into the .NET Framework; a component developer does not have to do any additional work to take advantage of the base design-time functionality.

For more information about design-time support, see Design-Time Attributes for Components and Enhancing Design-Time Support.

Hosting a Component

A component can be sited (hosted) in a container (defined later in this topic). When a component is sited, it interacts with the container through its site (defined later in this topic) and has the ability to query and get services from its container through the site. To ensure that resources are released when a container is torn down, a container must implement the IDisposable interface. In its implementation of the Dispose method, a container must release all resources that it holds and invoke the Dispose method of each of its contained components.

Containment is logical and need not have a visual representation. A middle-tier container that sites database components is an example of nonvisual containment. Visual containment is seen in the Windows Forms designer and the Web Forms designer in Visual Studio .NET. The visual design surface is a container that hosts the form component (in Web Forms, the page component).

Marshaling a Component

Components can be remotable or nonremotable. Remotable components are marshaled by reference or by value. Marshaling involves sending objects across boundaries such as application domains (lightweight processes), processes, and even machines. When an object is marshaled by reference, a proxy is created that makes remote calls to the object. When an object is marshaled by value, a serialized copy of the object is sent across the relevant boundary.

Remotable components that encapsulate system resources, that are large, or that exist as single instances should be marshaled by reference. The base class for components that are marshaled by reference is System.ComponentModel.Component. This base class implements IComponent and derives from MarshalByRefObject. Many components in the .NET Framework class library derive from Component, including System.Windows.Forms.Control (the base class for Windows Forms controls), System.Web.Services.WebService (the base class for XML Web services created using ASP.NET), and System.Timers.Timer (a class that generates recurring events).

Remotable components that simply hold state should be marshaled by value. The base class for components that are marshaled by value is System.ComponentModel.MarshalByValueComponent. This base class implements IComponent and derives from Object. Only a few components in the .NET Framework class library derive from MarshalByValueComponent. All such components are in the System.Data namespace (DataColumn, DataSet, DataTable, DataView, and DataViewManager).

Note   The base classes for objects that are marshaled by value and by reference are Object and MarshalByRefObject, respectively, but the corresponding derived classes are named MarshalByValueComponent and Component. The logic behind the naming scheme is that the more commonly used type has the simpler name.

If a component will not be remoted, do not derive from the base implementations for Component; instead, implement IComponent directly.

For more information about object remoting, see .NET Remoting Overview.

Control

A control is a component that provides (or enables) user-interface (UI) capabilities. The .NET Framework provides two base classes for controls: one for client-side Windows Forms controls and the other for ASP.NET server controls. These are System.Windows.Forms.Control and System.Web.UI.Control. All controls in the .NET Framework class library derive directly or indirectly from these two classes. System.Windows.Forms.Control derives from Component and itself provides UI capabilities. System.Web.UI.Control implements IComponent and provides the infrastructure on which it is easy to add UI functionality.

Note   Every control is a component, but the converse is not true.

Container and Site

If you are developing components and controls for Windows Forms or for Web Forms pages (ASP.NET pages), you do not have to implement containers or sites. The designers for Windows Forms and for Web Forms are containers for Windows Forms and for ASP.NET server controls. Containers provide services to the components and controls sited within them. At design time, controls are sited in the designer and obtain services from the designer. For completeness, the definitions of a container and a site are given below.

  • Container
    A container is a class that implements the System.ComponentModel.IContainer interface or derives from a class that implements this interface. A container logically contains one or more components that are called the container's child components.
  • Site
    A site is a class that implements the System.ComponentModel.ISite interface or derives from a class that implements this interface. Sites are provided by a container to manage and communicate with its child components. Typically, a container and a site are implemented as a unit.

See Also

Properties Overview | Design-Time Attributes for Components | Developing Windows Forms Controls | Developing ASP.NET Server Controls | Enhancing Design-Time Support