Inicialización y finalización de componentes
Un componente se inicializa por su constructor (SubNew en Visual Basic) y se destruye por su destructor (SubFinalizeen Visual Basic).Se llama al constructor del componente cuando se crea una instancia de éste; después, no es posible llamar al constructor.La llamada al destructor se realiza inmediatamente antes de destruirlo mediante la recolección de elementos no utilizados y la reclamación de la memoria que ocupa.
Nota para Visual Basic |
---|
En versiones anteriores de Visual Basic, los eventos Initialize y Terminate servían para el mismo propósito que el constructor y el destructor. |
Esperar la recolección de elementos no utilizados
Una vez que la recolección de elementos no utilizados determina que el componente ya no está al alcance de ningún código en ejecución, Common Language Runtime llama al destructor del componente.Esto sucede si se liberaron todas las referencias al componente o si las únicas referencias al componente las mantienen objetos aislados de forma similar de todo el código en ejecución, por ejemplo, en el caso de referencias circulares.
Puesto que puede producirse un retardo entre el momento en que un usuario termina con el componente y el momento en que se llama a su destructor, en la duración de los componentes de .NET Framework se introdujo un paso adicional: si el componente adquiere recursos del sistema, como conexiones de base de datos o controladores de objetos del sistema Windows, se debe implementar la interfaz IDisposable y proporcionar un método Dispose, de modo que los usuarios del componente puedan elegir cuándo se liberan esos recursos.
Ciclo de vida de un componente
Inicialización de tipo: cuando se crea la primera instancia del componente, el primer código que se ejecuta es el código de inicialización compartido.Las referencias a cualquier miembro compartido también harán que se ejecute el constructor compartido.Esto incluye todos los campos compartidos (variables miembro) inicializados y el constructor compartido (SharedSubNew), si existe.En el código siguiente se crea una fuente de referencia para toda la clase.
[!NOTA]
La palabra clave de C# que corresponde a Shared es static, que no debe confundirse con la palabra clave Static de Visual Basic.
Public Class ADrawing
Shared ReadOnly ReferenceFont As New Font("TimesNewRoman", 14)
' Shared constructor does not overload other constructors.
Shared Sub New()
' There is no call to the base class's shared constructor.
' Insert code to initialize the shared data.
End Sub
End Class
class ADrawing
{
static Font m_referenceFont = new Font("TimesNewRoman", 14);
// Simply add the static keyword to create a static constructor.
// Static constructors do not have any parameters.
static ADrawing()
{
// There is no call to the base class's static constructor.
// Code to initialize the font here.
}
}
[!NOTA]
La inicialización de la clase puede producirse aunque no se cree ninguna instancia del componente.Por ejemplo, se inicializará una clase abstract (MustInherit) con funciones de miembros compartidas y esas funciones estarán disponibles para su uso en la aplicación, aunque no se cree ninguna instancia de la clase.
Inicialización de instancia: cuando se crea una instancia del componente, se inicializan los miembros de datos que tienen código de inicialización y se ejecuta la sobrecarga del constructor correspondiente.En el código siguiente se inicializa un campo privado y se definen dos constructores: uno al que se llamará si no hay ningún parámetro y otro al que se llamará si el usuario especifica parámetros.
Class AShape Private answer As Integer = 42 Public Sub New() ' Call another constructor with default initialization values. MyClass.New(System.Drawing.Color.Red, 5280, DefinedSizes.Large) End Sub Public Overloads Sub New(myColor As Color, myLength As Integer, _ Size As DefinedSizes) ' Insert code to initialize the class. End Sub ' Defines the DefinedSizes enum Public Enum DefinedSizes Large Small End Enum End Class
class AShape { private int m_answer = 42; // Forward to another constructor. public AShape() : this(System.Drawing.Color.Red, 5280, DefinedSizes.Large) { // Additional initialization goes here. } public AShape(Color color, int length, DefinedSizes size) { // Code to initialize the class goes here. } // Defines the DefinedSizes enum public enum DefinedSizes { Large, Small } }
Eliminación de recursos: si el componente implementa la interfaz IDisposable, debe proporcionar un método Dispose, al que el cliente debe llamar cuando termine de usar el componente.Tenga en cuenta que cualquier componente que herede de Component ya tiene una implementación predeterminada de Dispose, que se puede reemplazar para proporcionar código adicional de limpieza.En el método Dispose, el componente libera todos los recursos del sistema que puede haber asignado, libera referencias a otros objetos y se presenta como inutilizable.También puede haber instancias donde sea apropiado que el componente llame a su propio método Dispose.En el código siguiente se elimina un objeto dependiente que tenga un método Dispose.
' Assumes that the class implements IDisposable Public Sub Dispose() Implements IDisposable.Dispose myWidget.Dispose myWidget = Nothing ' Insert additional code. End Sub
// Assumes that the class implements IDisposable public void IDisposable.Dispose() { mywidget.Dispose(); mywidget = null; // Dispose of remaining objects. }
Después de llamar a Dispose, el cliente debe liberar todas las referencias restantes al componente, de modo que la recolección de elementos no utilizados pueda recuperar la memoria del componente.
Instance destruction: Cuando la recolección de elementos no utilizados detecta que no queda ninguna referencia al componente, el runtime llama al destructor del componente (Finalizeen Visual Basic) y libera memoria.Debe reemplazar el método Finalize de la clase base (para Visual Basic) o implementar un destructor (para Visual c#) con el fin de implementar su propio código de limpieza, pero siempre debe incluir una llamada al destructor o al método Finalize de la clase base.
Protected Overrides Sub Finalize() m_Gadget = Nothing m_Gear = Nothing MyBase.Finalize() End Sub
// In C#, a destructor is used instead of a Finalize method. ~ThisClass() { m_gadget = null; m_gear = null; // The base class finalizer is called automatically }
¿Cuándo debe implementarse un método Dispose?
Si el componente hereda de Component, se proporciona una implementación predeterminada de Dispose.Esta implementación puede reemplazarse para proporcionar código de limpieza personalizado.Si genera un componente mediante la compilación de una implementación personalizada de IComponent, es recomendable que implemente IDisposable para proporcionar al componente un método Dispose.
El componente necesitará un método Dispose si asigna objetos del sistema, conexiones de base de datos u otros recursos escasos que deban liberarse tan pronto como el usuario termine con el componente.
También debe implementarse un método Dispose si el componente contiene referencias a otros objetos que tengan métodos Dispose.
¿Por qué implementar Dispose?
Según cuál sea la actividad del sistema, puede transcurrir un intervalo de tiempo impredecible entre el momento en que el usuario termina de utilizar el componente y el momento en que la recolección de elementos no utilizados detecta que el código del componente está fuera de alcance.Si no proporciona un método Dispose, el componente continuará reteniendo sus recursos durante este intervalo.
Un escenario pesimista
Imagine un componente de servidor que utilice una conexión de base de datos y no tenga un método Dispose.En un servidor con una gran cantidad de memoria, podría crear y liberar muchas instancias del componente sin producir un gran impacto sobre la memoria libre.En este caso, la recolección de elementos no utilizados podría no destruir los componentes durante algún tiempo después de que se liberen las referencias a estos componentes.
Finalmente, todas las conexiones de base de datos disponibles podrían estar ocupadas por componentes liberados pero no destruidos.Aunque el servidor no experimentara escasez de memoria, podría ser incapaz de responder a las solicitudes del usuario.
Vea también
Tareas
Cómo: Crear y configurar componentes en modo de diseño
Referencia
Conceptos
Características de clases de componentes
Cambios en la creación de instancias de componentes en Visual Basic