Compartir a través de


Clase frente a componente y frente a control

En este tema se definen los términos componente y control; estas explicaciones le ayudarán a decidir cuándo debe implementar una clase que sea un componente o un control.

Nota

En este tema se analiza Windows Forms y las clases de ASP.NET.Esta explicación no se aplica a las clases de WPF. Para obtener información sobre cómo crear controles de WPF, vea Información general sobre la creación de controles.

La siguiente lista incluye exhaustivas instrucciones para los implementadores.

  • Si la clase usa recursos externos pero no se va a emplear en una superficie de diseño, implemente IDisposable o derive de una clase que implemente IDisposable de forma directa o indirecta.

  • Si la clase se va a usar en una superficie de diseño (como el diseñador de Windows Forms o formularios Web Forms), implemente IComponent o derive de una clase que implemente IComponent de forma directa o indirecta. Observe que IComponent extiende IDisposable, por lo que un tipo IComponent es siempre un tipo IDisposable. Un tipo IComponent tiene una pequeña sobrecarga de rendimiento con respecto a un tipo IDisposable que no sea IComponent, pero esto se suele compensar por la posibilidad de ubicar un tipo IComponent en tiempo de diseño y en tiempo de ejecución. (La ubicación se explica más adelante en este tema.)

  • Si desea disponer de una clase que se pueda diseñar (usar en una superficie de diseño) y cuyas referencias se calculen por referencia, puede derivar de Component. Component es la implementación base de un tipo IComponent cuyas referencias se calculan por referencia.

  • Si desea disponer de una clase diseñable cuyas referencias se calculen por valor, puede derivar de MarshalByValueComponent. MarshalByValueComponent es la implementación base de un tipo IComponent cuyas referencias se calculan por valor.

  • Si desea introducir un tipo IComponent en la jerarquía de modelos de objeto y no se puede derivar de una implementación base como Component o MarshalByValueComponent debido a una herencia simple, implemente IComponent.

  • Si desea obtener una clase que se pueda diseñar y que proporcione una interfaz de usuario, la clase es un control. Un control debe derivarse directa o indirectamente de una de las clases de control base: Control o Control.

    Nota

    Si la clase no se puede diseñar ni contiene recursos externos, no son precisos los tipos IComponent e IDisposable.

A continuación figuran las definiciones de componente, control, contenedor y sitio.

Componente

En .NET Framework, un componente es una clase que implementa la interfaz IComponent o se deriva directa o indirectamente de una clase que implementa IComponent. En programación, el término componente se utiliza normalmente para objetos que se pueden volver a utilizar y que pueden interactuar con otros objetos. Un componente de .NET Framework cumple esos requisitos generales y, además, dispone de características como control sobre recursos externos y compatibilidad en tiempo de diseño.

Control sobre recursos externos

La interfaz IComponent extiende la interfaz IDisposable, que tiene un método denominado Dispose en su contrato. En su implementación del método Dispose, un componente debe liberar los recursos externos de forma explícita. Esta es una manera determinista de liberar recursos, en contraste con la limpieza no determinista predeterminada que sucede durante la recolección de elementos no utilizados. Los desarrolladores deben propagar Disposeen una jerarquía de contención para asegurarse de que los elementos secundarios de un componente también liberan recursos. Además, un componente derivado debe invocar al método Dispose de su clase base.

Nota

Aunque proporcione control explícito sobre los recursos mediante Dispose, siempre debe realizar una limpieza implícita mediante el finalizador (destructor) para evitar que los recursos se pierdan de forma permanente si un usuario no llama a Dispose en el componente.

En el siguiente ejemplo se muestra el modelo de implementación de Dispose en un componente base y en un componente derivado.

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

Compatibilidad en tiempo de diseño

Una característica importante de los componentes de .NET Framework es que se pueden diseñar; es decir, que una clase que es un componente puede utilizarse en un entorno de programación rápida de aplicaciones (RAD) como Visual Studio. Un componente se puede agregar al cuadro de herramientas de Visual Studio, se puede arrastrar y colocar en un formulario, y se puede manipular en una superficie de diseño. Observe que .NET Framework incorpora compatibilidad en tiempo de diseño con los tipos IComponent; un desarrollador de componentes no tiene que realizar ningún trabajo adicional para aprovechar la funcionalidad base en tiempo de diseño.

Para obtener más información sobre la compatibilidad en tiempo de diseño, vea Atributos en tiempo de diseño para componentes y Ampliar compatibilidad en tiempo de diseño.

Hospedar un componente

Un componente se puede ubicar (hospedar) en un contenedor (definido más adelante en este tema). Cuando se ubica un componente, interactúa con el contenedor a través de su sitio (definido más adelante en este tema), y puede consultar y obtener servicios de su contenedor a través del sitio. Para asegurarse de que los recursos se liberan cuando el contenedor deje de usarse, el contenedor debe implementar la interfaz IDisposable. En su implementación del método Dispose, un contenedor debe liberar todos los recursos que mantiene e invocar al método Dispose de cada uno de los componentes que contiene.

La contención es lógica y no necesita tener representación visual. Un ejemplo de contención no visual es un contenedor de nivel medio que hospeda componentes de base de datos. La contención visual se ve en los diseñadores de Windows Forms y formularios Web Forms de Visual Studio. La superficie de diseño visual es un contenedor que hospeda el componente de formulario (en formularios Web Forms, el componente de página).

Calcular las referencias de un componente

Los componentes pueden ser de uso remoto o de uso no remoto. Las referencias de los componentes de uso remoto se calculan por referencia o por valor. El cálculo de referencias implica el envío de objetos más allá de los límites, como Dominios de aplicación (procesos ligeros), procesos e incluso equipos. Cuando las referencias de un objeto se calculan por referencia, se crea un proxy que realiza llamadas remotas al objeto. Cuando las referencias de un objeto se calculan por valor, se envía una copia serializada del objeto a través de los límites relevantes.

Las referencias de los componentes de uso remoto que encapsulan recursos del sistema, que son grandes o que existen como instancias únicas, se deben calcular por referencia. La clase base de los componentes cuyas referencias se calculan por referencia es Component. Esta clase base implementa la interfaz IComponent y deriva de MarshalByRefObject. Muchos componentes de la biblioteca de clases de .NET Framework se derivan de Component, incluidos Control (la clase base de los controles de formularios Windows Forms), WebService (la clase base de los servicios Web XML creados mediante ASP.NET) y Timer (una clase que genera eventos recurrentes).

Las referencias de los componentes de uso remoto que sólo guardan un estado se deben calcular por valor. La clase base de los componentes cuyas referencias se calculan por valor es MarshalByValueComponent. Esta clase base implementa la interfaz IComponent y deriva de Object. Sólo unos pocos componentes de la biblioteca de clases de .NET Framework derivan de MarshalByValueComponent. Todos esos componentes están en el espacio de nombres System.Data (DataColumn, DataSet, DataTable, DataView y DataViewManager).

Nota

Las clases base de los objetos cuyas referencias se calculan por valor y por referencia son Object y MarshalByRefObject, respectivamente, pero las clases derivadas correspondientes se denominan MarshalByValueComponent y Component.La razón de la utilización de este esquema de nombres es que el tipo utilizado más habitualmente tiene el nombre más sencillo.

Si un componente no va a ser remoto, no debe derivarse de las implementaciones base de Component; en su lugar, implemente IComponent directamente.

Control

Un control es un componente que proporciona o habilita funciones de la interfaz de usuario. .NET Framework dispone de dos clases base para controles: una para controles de formularios Windows Forms del cliente y otra para controles de servidor de ASP.NET. Éstas son Control y Control. Todos los controles de la biblioteca de clases de .NET Framework se derivan directa o indirectamente de estas dos clases. Control se deriva de Component y proporciona funciones de interfaz de usuario. Control implementa IComponent y proporciona la infraestructura en la se puede agregar fácilmente funcionalidad de interfaz de usuario.

Nota

Todos los controles son componentes, pero no al revés.

Contenedor y sitio

Si va a programar componentes y controles para formularios Windows Forms o para páginas de formularios Web Forms (páginas de ASP.NET), no es necesario implementar contenedores o sitios. Los diseñadores de Windows Forms y de formularios Web Forms son contenedores de formularios Windows Forms y de los controles de servidor de ASP.NET. Los contenedores proporcionan servicios a los componentes y controles hospedados en ellos. En tiempo de diseño, los controladores se hospedan en el diseñador y obtienen servicios del mismo. Para ofrecer más detalles, a continuación se ofrecen las definiciones de contenedor y sitio.

  • Container
    Un contenedor es una clase que implementa la interfaz IContainer o que deriva de una clase que implementa esta interfaz. De forma lógica, un contenedor contiene uno o varios componentes, que se denominan componentes secundarios del contenedor.

  • Site
    Un sitio es una clase que implementa la interfaz ISite o que deriva de una clase que implementa esta interfaz. Un contenedor proporciona los sitios para administrar y comunicarse con sus componentes secundarios. Normalmente, un contenedor y un sitio se implementan como una unidad.

Vea también

Conceptos

Información general sobre propiedades

Atributos en tiempo de diseño para componentes

Otros recursos

Desarrollar controles personalizados de formularios Windows Forms con .NET Framework

Developing Custom ASP.NET Server Controls

Ampliar compatibilidad en tiempo de diseño