Este artículo se tradujo automáticamente. Para ver el artículo en inglés, active la casilla Inglés. Además, puede mostrar el texto en inglés en una ventana emergente si mueve el puntero del mouse sobre el texto.
Traducción
Inglés

Object.Finalize (Método) ()

 

Permite que un objeto intente liberar recursos y realizar otras operaciones de limpieza antes de ser reclamado por el recolector de basura.

Espacio de nombres:   System
Ensamblado:  mscorlib (en mscorlib.dll)

protected virtual void Finalize()

El Finalize se utiliza para realizar operaciones de limpieza en los recursos no administrados mantenidos por el objeto actual antes de que se destruya el objeto.El método está protegido y, por tanto, es accesible sólo a través de esta clase o una clase derivada.

En esta sección:

El Object clase no proporciona una implementación para el Finalize método y el recolector de elementos no utilizados no marca los tipos derivados de Object para la finalización a menos que invalide el Finalize método.

Si un tipo reemplaza el Finalize método, el recolector de elementos no utilizados agrega una entrada para cada instancia del tipo a una estructura interna denominada cola de finalización.La cola de finalización contiene entradas para todos los objetos del montón administrado cuyo código de finalización debe ejecutar antes de que el recolector de elementos no utilizados reclame su memoria.El recolector de elementos no utilizados, a continuación, llama el Finalize método automáticamente en las siguientes condiciones:

  • Después de que el recolector de elementos no utilizados ha detectado que un objeto es inaccesible, a menos que haya sido excluido del proceso de finalización mediante una llamada a la GC.SuppressFinalize (método).

  • Durante el cierre de un dominio de aplicación, a menos que el objeto está exento de la finalización.Durante el cierre, se finalizarán incluso objetos que siguen siendo accesibles.

Finalize se llama automáticamente sólo una vez en una instancia determinada, a menos que el objeto se registre de nuevo mediante un mecanismo como GC.ReRegisterForFinalize y GC.SuppressFinalize método no se ha llamado posteriormente.

Finalize las operaciones tienen las siguientes limitaciones:

  • El tiempo exacto cuando se ejecuta el finalizador es indefinido.Para garantizar la liberación determinista de recursos para implementar las instancias de la clase, un Close método o proporcionar un IDisposable.Dispose implementación.

  • Los finalizadores de dos objetos no se garantiza para ejecutarse en un orden determinado, aunque un objeto haga referencia a otro.Es decir, si un objeto tiene una referencia al objeto B y ambos tienen finalizadores, objeto B podría ya ha finalizado cuando se inicia el finalizador del objeto.

  • El subproceso en el que se ejecuta el finalizador no está especificado.

El Finalize método podría no ejecutarse hasta su finalización o puede que no llegue a ejecutarse en las siguientes circunstancias excepcionales:

  • Si otro finalizador se bloquea de forma indefinida (pasa a un bucle infinito, intenta obtener un bloqueo, nunca puede obtener y así sucesivamente).Dado que el tiempo de ejecución intenta ejecutar los finalizadores hasta su finalización, podrían no se llame a otros finalizadores si un finalizador se bloquea de forma indefinida.

  • Si el proceso termina sin que el tiempo de ejecución pueda limpiar.En este caso, la primera notificación de terminación del proceso de tiempo de ejecución es una notificación DLL_PROCESS_DETACH.

El tiempo de ejecución continúa finalizar los objetos durante el cierre sólo si el número de objetos susceptibles de finalización sigue reduciéndose.

Si Finalize o un reemplazo de Finalize produce una excepción y el tiempo de ejecución no está hospedado por una aplicación que reemplace la directiva predeterminada, dicho motor finalizará el proceso y no activa try/finally se ejecutan los finalizadores ni bloques.Este comportamiento garantiza la integridad del proceso si el finalizador no puede liberar ni destruir recursos.

Debe reemplazar Finalize para una clase que utiliza recursos no administrados como identificadores de archivo o base de datos de las conexiones que se deben liberar cuando se descarta el objeto administrado que se usa durante la recolección de elementos no utilizados.

System_CAPS_importantImportante

Si un SafeHandle objeto está disponible que ajusta el recurso no administrado, la alternativa recomendada es implementar el patrón dispose con un controlador seguro y no reemplazar Finalize.Para obtener más información, consulte alternativa SafeHandle The sección.

El Object.Finalize método no hace nada de forma predeterminada, pero se debe invalidar Finalize sólo si es necesario y sólo para liberar recursos no administrados.Reclamar memoria suele tardar mucho más tiempo si se ejecuta una operación de finalización, ya que requiere al menos dos recolecciones de elementos no utilizados.Además, debe reemplazar el Finalize sólo los tipos de método de referencia.Common language runtime finaliza sólo los tipos de referencia.Omite los finalizadores en los tipos de valor.

Todas las implementaciones de Finalize en un tipo derivado debe llamar a la implementación de su tipo base de Finalize.Este es el único caso en la aplicación que puede llamar código Finalize.

System_CAPS_noteNota

El compilador de C# no permite invalidar el Finalize método.En su lugar, proporcionar un finalizador implementando un para la clase.Un destructor de C# automáticamente llama al destructor de su clase base.

Visual C++ también proporciona su propia sintaxis para implementar el Finalize método.Para obtener más información, vea la sección "Destructores y finalizadores" de How to: Define and Consume Classes and Structs (C++/CLI).

Dado que la colección de elementos no utilizados es no determinista, no conoce con precisión cuando el recolector de elementos no utilizados realiza finalización.Para liberar recursos inmediatamente, también puede implementar la y IDisposable (interfaz).El IDisposable.Dispose implementación puede llamar a los consumidores de la clase para liberar recursos no administrados, y puede usar el Finalize método para liberar recursos no administrados en caso de que el Dispose no se llama el método.

Finalize puede tomar casi cualquier acción, como el restablecimiento de un objeto (que es, hacer que el objeto accesible nuevo) después de que se ha limpiado durante la recolección.Sin embargo, el objeto sólo puede restablecerse una vez; Finalize no se puede llamar en objetos restablecidos durante la recolección de elementos no utilizados.Hay una acción que la implementación de Finalize nunca debe tomar: nunca debe producir una excepción.

Crear los finalizadores confiables a menudo es difícil, puesto que no pueden realizar suposiciones sobre el estado de la aplicación y no controlada de excepciones del sistema como OutOfMemoryException y StackOverflowException Finalizar el finalizador.En lugar de implementar un finalizador para la clase para liberar recursos no administrados, puede usar un objeto que se deriva de la System.Runtime.InteropServices.SafeHandle clase para encapsular los recursos no administrados y, a continuación, implemente el patrón dispose sin un finalizador..NET Framework proporciona las siguientes clases en el Microsoft.Win32 espacio de nombres que se derivan de System.Runtime.InteropServices.SafeHandle:

En el ejemplo siguiente se usa el con controladores seguros en lugar de reemplazar el Finalize método.Define un FileAssociation clase que contiene la información del registro acerca de la aplicación que trata los archivos con una extensión de archivo determinada.Los identificadores de dos registro devueltos como out parámetros Windows RegOpenKeyEx llamadas a funciones se pasan a la SafeRegistryHandle constructor.Protegido el tipo Dispose a continuación, se llama el método la SafeRegistryHandle.Dispose método para liberar estos dos puntos de control.

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;

public class FileAssociationInfo : IDisposable
{
   // Private variables.
   private String ext;
   private String openCmd;
   private String args;
   private SafeRegistryHandle hExtHandle, hAppIdHandle;

   // Windows API calls.
   [DllImport("advapi32.dll", CharSet= CharSet.Auto, SetLastError=true)]
   private static extern int RegOpenKeyEx(IntPtr hKey, 
                  String lpSubKey, int ulOptions, int samDesired,
                  out IntPtr phkResult);
   [DllImport("advapi32.dll", CharSet= CharSet.Unicode, EntryPoint = "RegQueryValueExW",
              SetLastError=true)]
   private static extern int RegQueryValueEx(IntPtr hKey,
                  string lpValueName, int lpReserved, out uint lpType, 
                  string lpData, ref uint lpcbData);   
   [DllImport("advapi32.dll", SetLastError = true)]
   private static extern int RegSetValueEx(IntPtr hKey, [MarshalAs(UnmanagedType.LPStr)] string lpValueName,
                  int Reserved, uint dwType, [MarshalAs(UnmanagedType.LPStr)] string lpData,
                  int cpData);
   [DllImport("advapi32.dll", SetLastError=true)]
   private static extern int RegCloseKey(UIntPtr hKey);

   // Windows API constants.
   private const int HKEY_CLASSES_ROOT = unchecked((int) 0x80000000);
   private const int ERROR_SUCCESS = 0;

    private const int KEY_QUERY_VALUE = 1;
    private const int KEY_SET_VALUE = 0x2;

   private const uint REG_SZ = 1;

   private const int MAX_PATH = 260;

   public FileAssociationInfo(String fileExtension)
   {
      int retVal = 0;
      uint lpType = 0;

      if (!fileExtension.StartsWith("."))
             fileExtension = "." + fileExtension;
      ext = fileExtension;

      IntPtr hExtension = IntPtr.Zero;
      // Get the file extension value.
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0, KEY_QUERY_VALUE, out hExtension);
      if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);
      // Instantiate the first SafeRegistryHandle.
      hExtHandle = new SafeRegistryHandle(hExtension, true);

      string appId = new string(' ', MAX_PATH);
      uint appIdLength = (uint) appId.Length;
      retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, out lpType, appId, ref appIdLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);
      // We no longer need the hExtension handle.
      hExtHandle.Dispose();

      // Determine the number of characters without the terminating null.
      appId = appId.Substring(0, (int) appIdLength / 2 - 1) + @"\shell\open\Command";

      // Open the application identifier key.
      string exeName = new string(' ', MAX_PATH);
      uint exeNameLength = (uint) exeName.Length;
      IntPtr hAppId;
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), appId, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
                            out hAppId);
       if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);

      // Instantiate the second SafeRegistryHandle.
      hAppIdHandle = new SafeRegistryHandle(hAppId, true);

      // Get the executable name for this file type.
      string exePath = new string(' ', MAX_PATH);
      uint exePathLength = (uint) exePath.Length;
      retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, out lpType, exePath, ref exePathLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);

      // Determine the number of characters without the terminating null.
      exePath = exePath.Substring(0, (int) exePathLength / 2 - 1);
      // Remove any environment strings.
      exePath = Environment.ExpandEnvironmentVariables(exePath);

      int position = exePath.IndexOf('%');
      if (position >= 0) {
         args = exePath.Substring(position);
         // Remove command line parameters ('%0', etc.).
         exePath = exePath.Substring(0, position).Trim();
      }
      openCmd = exePath;   
   }

   public String Extension
   { get { return ext; } }

   public String Open
   { get { return openCmd; } 
     set {
        if (hAppIdHandle.IsInvalid | hAppIdHandle.IsClosed)
           throw new InvalidOperationException("Cannot write to registry key."); 
        if (! File.Exists(value)) {
           string message = String.Format("'{0}' does not exist", value);
           throw new FileNotFoundException(message); 
        }
        string cmd = value + " %1";
        int retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, 
                                   REG_SZ, value, value.Length + 1);
        if (retVal != ERROR_SUCCESS)
           throw new Win32Exception(retVal);                          
     } }

   public void Dispose() 
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }   

   protected void Dispose(bool disposing)
   {
      // Ordinarily, we release unmanaged resources here; 
      // but all are wrapped by safe handles.

      // Release disposable objects.
      if (disposing) {
         if (hExtHandle != null) hExtHandle.Dispose();
         if (hAppIdHandle != null) hAppIdHandle.Dispose();
      }
   }
}

En el ejemplo siguiente se comprueba que el Finalize se invoca cuando un objeto que reemplaza Finalize se destruye.Tenga en cuenta que, en una aplicación de producción, el Finalize se reemplazaría el método para liberar recursos no administrados mantenidos por el objeto.Tenga en cuenta también que el ejemplo de C# proporciona un destructor en lugar de reemplazar el Finalize método.

using System;
using System.Diagnostics;

public class ExampleClass
{
   Stopwatch sw;

   public ExampleClass()
   {
      sw = Stopwatch.StartNew();
      Console.WriteLine("Instantiated object");
   } 

   public void ShowDuration()
   {
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }

   ~ExampleClass()
   {
      Console.WriteLine("Finalizing object");
      sw.Stop();
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }
}

public class Demo
{
   public static void Main()
   {
      ExampleClass ex = new ExampleClass();
      ex.ShowDuration();
   }
}
// The example displays output like the following:
//    Instantiated object
//    This instance of ExampleClass has been in existence for 00:00:00.0011060
//    Finalizing object
//    This instance of ExampleClass has been in existence for 00:00:00.0036294

For an additional example that overrides the Finalize method, see the GC.SuppressFinalize method.

Universal Windows Platform
Disponible desde 4.5
.NET Framework
Disponible desde 1.1
Portable Class Library
Compatible con: portable .NET platforms
Silverlight
Disponible desde 2.0
Windows Phone Silverlight
Disponible desde 7.0
Windows Phone
Disponible desde 8.1
Volver al principio
Mostrar: