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

Método Object.Finalize ()

 

Publicado: octubre de 2016

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 Overridable Sub Finalize

El Finalize método se usa 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 marcar tipos derivados de Object para la finalización, a menos que invalide la Finalize método.

Si un tipo de invalidar 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 ejecutarse antes de que el recolector de elementos no utilizados pueda reclamar 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 el objeto 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 finalización. Durante el cierre, finalizados incluso objetos que siguen siendo accesibles.

Finalizese llama automáticamente una sola 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.

Finalizelas operaciones tienen las siguientes limitaciones:

  • La hora exacta cuando se ejecuta el finalizador es indefinida. Para garantizar la liberación determinista de recursos para implementar instancias de la clase, un Close método o proporcione un IDisposable.Dispose implementación.

  • No se garantizan que los finalizadores de dos objetos de ejecución en cualquier orden determinado, incluso si un objeto hace referencia a la otra. 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 podría no ejecutarse en absoluto en las siguientes circunstancias excepcionales:

  • Si otro finalizador se bloquea indefinidamente (queda en un bucle infinito, intenta obtener un bloqueo, nunca puede obtener y así sucesivamente). Dado 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 una oportunidad para 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 inicia una excepción y el tiempo de ejecución no está hospedado por una aplicación que reemplace la directiva predeterminada, el runtime finaliza el proceso y no active try/finally bloques o los finalizadores se ejecutan. Este comportamiento garantiza la integridad del proceso si el finalizador no puede liberar ni destruir recursos.

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

System_CAPS_importantImportante

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

El Object.Finalize método no hace nada de forma predeterminada, pero se debe invalidar Finalize solo si es necesario y solo para liberar recursos no administrados. Reclamar memoria suele tardar mucho más tiempo si se ejecuta una operación de finalización, porque requiere al menos dos recolecciones de elementos no utilizados. Además, debe invalidar el Finalize solo tipos de método como referencia. Common language runtime finaliza solo los tipos de referencia. Omite los finalizadores en 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 se puede llamar a código Finalize.

System_CAPS_noteNota

El compilador de C# no permite invalidar el Finalize método. En su lugar, proporciona un finalizador implementando un destructor para la clase. Un destructor de C# llama automáticamente 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 Cómo: definir y utilizar clases y Structs (CLI de C++).

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 elegir implementar la patrón de dispose y IDisposable interfaz. El IDisposable.Dispose implementación se 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.

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

Crear los finalizadores confiables a menudo es difícil, porque no se puede realizar suposiciones sobre el estado de la aplicación y que excepciones no controladas de sistema como OutOfMemoryException y StackOverflowException finalizar el finalizador. En lugar de implementar un finalizador de 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, implementar el patrón de 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 patrón de dispose con controladores seguros en lugar de reemplazar el Finalize método. Define un FileAssociation clase que contiene información de registro de la aplicación que trata los archivos con una extensión de archivo en particular. Los identificadores de dos registro formando out parámetros por Windows RegOpenKeyEx llamadas a funciones se pasan a la SafeRegistryHandle constructor. El tipo del protege Dispose método, a continuación, llama el SafeRegistryHandle.Dispose método para liberar estos dos puntos de control.

Imports Microsoft.Win32.SafeHandles
Imports System
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text

Public Class FileAssociationInfo : Implements IDisposable
   ' Private variables.
   Private ext As String
   Private openCmd As String
   Private args As String
   Private hExtHandle, hAppIdHandle As SafeRegistryHandle

   ' Windows API calls.
   Private Declare Unicode Function RegOpenKeyEx Lib"advapi32.dll" _
                   Alias "RegOpenKeyExW" (hKey As IntPtr, lpSubKey As String, _
                   ulOptions As Integer, samDesired As Integer, _
                   ByRef phkResult As IntPtr) As Integer
   Private Declare Unicode Function RegQueryValueEx Lib "advapi32.dll" _
                   Alias "RegQueryValueExW" (hKey As IntPtr, _
                   lpValueName As String, lpReserved As Integer, _
                   ByRef lpType As UInteger, lpData As String, _
                   ByRef lpcbData As UInteger) As Integer   
   Private Declare Function RegSetValueEx Lib "advapi32.dll" _
                  (hKey As IntPtr, _
                  <MarshalAs(UnmanagedType.LPStr)> lpValueName As String, _
                  reserved As Integer, dwType As UInteger, _
                  <MarshalAs(UnmanagedType.LPStr)> lpData As String, _
                  cpData As Integer) As Integer 
   Private Declare Function RegCloseKey Lib "advapi32.dll" _
                  (hKey As IntPtr) As Integer

   ' Windows API constants.
   Private Const HKEY_CLASSES_ROOT As Integer = &h80000000
   Private Const ERROR_SUCCESS As Integer = 0

   Private Const KEY_QUERY_VALUE As Integer = 1
   Private Const KEY_SET_VALUE As Integer = &h2

   Private REG_SZ As UInteger = 1

   Private Const MAX_PATH As Integer  = 260

   Public Sub New(fileExtension As String)
      Dim retVal As Integer = 0
      Dim lpType As UInteger = 0

      If Not fileExtension.StartsWith(".") Then 
         fileExtension = "." + fileExtension
      End If   
      ext = fileExtension

      Dim hExtension As IntPtr = IntPtr.Zero
      ' Get the file extension value.
      retVal = RegOpenKeyEx(New IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0, 
                            KEY_QUERY_VALUE, hExtension)
      if retVal <> ERROR_SUCCESS Then 
         Throw New Win32Exception(retVal)
      End If  
      ' Instantiate the first SafeRegistryHandle.
      hExtHandle = New SafeRegistryHandle(hExtension, True)

      Dim appId As New String(" "c, MAX_PATH)
      Dim appIdLength As UInteger = CUInt(appId.Length)
      retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, _
                               0, lpType, appId, appIdLength)
      if retVal <> ERROR_SUCCESS Then
         Throw New Win32Exception(retVal)
      End If   
      ' We no longer need the hExtension handle.
      hExtHandle.Dispose()

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

      ' Open the application identifier key.
      Dim exeName As New string(" "c, MAX_PATH)
      Dim exeNameLength As UInteger = CUInt(exeName.Length)
      Dim hAppId As IntPtr
      retVal = RegOpenKeyEx(New IntPtr(HKEY_CLASSES_ROOT), appId, 0, 
                            KEY_QUERY_VALUE Or KEY_SET_VALUE, hAppId)
      If retVal <> ERROR_SUCCESS Then 
         Throw New Win32Exception(retVal)
      End If   

      ' Instantiate the second SafeRegistryHandle.
      hAppIdHandle = New SafeRegistryHandle(hAppId, True)

      ' Get the executable name for this file type.
      Dim exePath As New string(" "c, MAX_PATH)
      Dim exePathLength As UInteger = CUInt(exePath.Length)
      retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), _
                               String.Empty, 0, lpType, exePath, exePathLength)
      If retVal <> ERROR_SUCCESS Then
         Throw New Win32Exception(retVal)
      End If     
      ' Determine the number of characters without the terminating null.
      exePath = exePath.Substring(0, CInt(exePathLength) \ 2 - 1)

      exePath = Environment.ExpandEnvironmentVariables(exePath)
      Dim position As Integer = exePath.IndexOf("%"c)
      If position >= 0 Then
         args = exePath.Substring(position)
         ' Remove command line parameters ('%0', etc.).
         exePath = exePath.Substring(0, position).Trim()
      End If   
      openCmd = exePath
   End Sub

   Public ReadOnly Property Extension As String
      Get
         Return ext
      End Get
   End Property

   Public Property Open As String
      Get
         Return openCmd
      End Get    
      Set 
        If hAppIdHandle.IsInvalid Or hAppIdHandle.IsClosed Then
           Throw New InvalidOperationException("Cannot write to registry key.")
        End If    
        If Not File.Exists(value) Then
           Dim message As String = String.Format("'{0}' does not exist", value)
           Throw New FileNotFoundException(message) 
        End If
        Dim cmd As String = value + " %1"
        Dim retVal As Integer = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, 
                                              REG_SZ, value, value.Length + 1)
        If retVal <> ERROR_SUCCESS Then 
           Throw New Win32Exception(retVal)
        End If                             
      End Set
   End Property   

   Public Sub Dispose() _
      Implements IDisposable.Dispose 
      Dispose(true)
      GC.SuppressFinalize(Me)
   End Sub   

   Protected Sub Dispose(disposing As Boolean)
      ' Ordinarily, we release unmanaged resources here 
      ' but all are wrapped by safe handles.

      ' Release disposable objects.
      If disposing Then
         If hExtHandle IsNot Nothing Then hExtHandle.Dispose()
         If hAppIdHandle IsNot Nothing Then hAppIdHandle.Dispose()
      End If
   End Sub
End Class

En el ejemplo siguiente se comprueba que la Finalize método se llama cuando un objeto que invalida 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.

Imports System.Diagnostics

Public Class ExampleClass
   Dim sw As StopWatch

   Public Sub New()
      sw = Stopwatch.StartNew()
      Console.WriteLine("Instantiated object")
   End Sub 

   Public Sub ShowDuration()
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        Me, sw.Elapsed)
   End Sub

   Protected Overrides Sub Finalize()
      Console.WriteLine("Finalizing object")
      sw.Stop()
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        Me, sw.Elapsed)
   End Sub
End Class

Module Demo
   Public Sub Main()
      Dim ex As New ExampleClass()
      ex.ShowDuration()
   End Sub
End Module
' 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 M:System.Object.Finalize method, see the M:System.GC.SuppressFinalize(System.Object) method.

Plataforma universal de Windows
Disponible desde 8
.NET Framework
Disponible desde 1.1
Biblioteca de clases portable
Se admite en: plataformas portátiles de .NET
Silverlight
Disponible desde 2.0
Windows Phone Silverlight
Disponible desde 7.0
Windows Phone
Disponible desde 8.1
Volver al principio
Mostrar: