Este artigo foi traduzido por máquina. Para visualizar o arquivo em inglês, marque a caixa de seleção Inglês. Você também pode exibir o texto Em inglês em uma janela pop-up, movendo o ponteiro do mouse sobre o texto.
Tradução
Inglês

Método Object.Finalize ()

 

Permite que um objeto tente liberar recursos e executar outras operações de limpeza antes que ele seja recuperado pela coleta de lixo.

Namespace:   System
Assembly:  mscorlib (em mscorlib.dll)

protected virtual void Finalize()

O Finalize método é usado para executar operações de limpeza de recursos não gerenciados mantidos pelo objeto atual antes do objeto é destruído. O método é protegido e, portanto, é acessível somente por meio dessa classe ou por meio de uma classe derivada.

Nesta seção:

O Object classe não fornece nenhuma implementação para o Finalize método e o coletor de lixo não marcar tipos derivados de Object finalização, a menos que elas substituem o Finalize método.

Se um tipo de substituir o Finalize método, o coletor de lixo adiciona uma entrada para cada instância do tipo para uma estrutura interna chamada fila de finalização. Fila de finalização contém entradas para todos os objetos no heap gerenciado, cujo código de finalização deve ser executado antes que o coletor de lixo possa recuperar a memória. O coletor de lixo, em seguida, chama o Finalize método automaticamente sob as seguintes condições:

  • Depois que o coletor de lixo descobriu que um objeto é inacessível, a menos que o objeto tem sido isentos de finalização por uma chamada para o GC.SuppressFinalize método.

  • Durante o desligamento de um domínio de aplicativo, a menos que o objeto é isento de finalização. Durante o desligamento, até mesmo os objetos que ainda são acessíveis são finalizados.

Finalizeé chamado automaticamente apenas uma vez em uma determinada instância, a menos que o objeto é registrado novamente usando um mecanismo como GC.ReRegisterForFinalize e GC.SuppressFinalize método não foi chamado subsequentemente.

Finalizeas operações têm as seguintes limitações:

  • A hora exata em que é executado o finalizador é indefinida. Para garantir a versão determinística de recursos para instâncias de sua classe, implementar um Close método ou forneça um IDisposable.Dispose implementação.

  • Finalizadores de dois objetos não são garantidos para ser executado em qualquer ordem específica, mesmo se um objeto se refere ao outro. Ou seja, se o objeto A tem uma referência ao objeto B e têm finalizadores, objeto B pode já ter sido finalizado quando inicia o finalizador do objeto A.

  • O thread no qual é executado o finalizador não está especificado.

O Finalize método não podem ser executadas até a conclusão ou talvez não sejam executadas nas seguintes circunstâncias excepcionais:

  • Se outro finalizador bloqueado indefinidamente (entrar em um loop infinito, tenta obter um bloqueio nunca pode obter e assim por diante). Porque o tempo de execução tenta executar finalizadores até a conclusão, outros finalizadores podem não ser chamadas se blocos um finalizador indefinidamente.

  • Se o processo é encerrado sem oferecendo a oportunidade para limpar o tempo de execução. Nesse caso, a primeira notificação do tempo de execução do encerramento do processo é uma notificação de DLL_PROCESS_DETACH.

O tempo de execução continua a finalizar objetos durante o desligamento somente enquanto o número de objetos finalizáveis continua diminuindo.

Se Finalize ou uma substituição de Finalize lançará uma exceção e o tempo de execução não é hospedado por um aplicativo que substitui a política padrão, o tempo de execução encerra o processo e nenhum ativo try/finally finalizadores ou blocos são executados. Esse comportamento garante a integridade do processo se o finalizador não pode liberar ou destruir os recursos.

Você deve substituir Finalize para uma classe que usa recursos não gerenciados, como identificadores de arquivos ou conexões que devem ser liberadas quando o objeto gerenciado que usa é descartado durante a coleta de lixo de banco de dados.

System_CAPS_importantImportante

Se um SafeHandle o objeto está disponível que encapsula seu recurso não gerenciado, a alternativa recomendada é implementar o padrão dispose com um identificador seguro e não substituir Finalize. Para obter mais informações, consulte SafeHandle a alternativa seção.

O Object.Finalize método não fará nada por padrão, mas você deve substituir Finalize somente se necessário e somente para liberar recursos não gerenciados. Recuperação de memória tende a levar mais tempo se uma operação de finalização é executado, porque ele requer pelo menos duas coletas de lixo. Além disso, você deve substituir a Finalize apenas tipos de método para referência. O common language runtime finaliza somente tipos de referência. Ele ignora os finalizadores em tipos de valor.

Cada implementação do Finalize em um tipo derivado deve chamar a implementação do tipo base do Finalize. Esse é o caso apenas em qual aplicativo o código tem permissão para chamar Finalize.

System_CAPS_noteObservação

O compilador c# não permitem que você substitua o Finalize método. Em vez disso, você fornece um finalizador implementando um destruidor para sua classe. Um destruidor c# chama automaticamente o destruidor de sua classe base.

Visual C++ também fornece sua própria sintaxe para implementar o Finalize método. Para obter mais informações, consulte a seção "Destruidores e finalizadores" de Como: definir e consumir Classes e estruturas (C++ /CLI).

Como a coleta de lixo é não determinística, você não saberá precisamente quando o coletor de lixo realiza a finalização. Para liberar os recursos imediatamente, também é possível implementar a dispose padrão e IDisposable interface. O IDisposable.Dispose implementação pode ser chamada pelos consumidores de sua classe para liberar recursos não gerenciados e você pode usar o Finalize método para liberar recursos não gerenciados no caso em que o Dispose método não for chamado.

Finalizepode levar a praticamente qualquer ação, inclusive trazer de volta um objeto (isto é, fazendo com que o objeto acessível novamente) depois que ele foi limpo durante a coleta de lixo. No entanto, o objeto pode somente ser reativado uma vez; Finalize não pode ser chamado em objetos Ressuscitados durante a coleta de lixo. Há uma ação que sua implementação de Finalize nunca deve levar: ele nunca deve lançar uma exceção.

Criar finalizadores confiáveis pode ser difícil, pois você não pode fazer suposições sobre o estado do seu aplicativo e sem tratamento de exceções do sistema, como OutOfMemoryException e StackOverflowException encerrar o finalizador. Em vez de implementar um finalizador para sua classe para liberar recursos não gerenciados, você pode usar um objeto que é derivado de System.Runtime.InteropServices.SafeHandle classe para encapsular os recursos não gerenciados e, em seguida, implemente o padrão dispose sem um finalizador. O .NET Framework fornece as seguintes classes de Microsoft.Win32 namespace que são derivados de System.Runtime.InteropServices.SafeHandle:

O exemplo a seguir usa o dispose padrão com identificadores de segurança em vez de substituir o Finalize método. Define um FileAssociation classe que encapsula informações de registro sobre o aplicativo que lida com arquivos com uma extensão de arquivo específico. Os identificadores de duas registro retornados como out parâmetros pelo Windows RegOpenKeyEx chamadas de função são passadas para o SafeRegistryHandle construtor. O tipo do protegida Dispose método chama o SafeRegistryHandle.Dispose método para liberar essas duas alças.

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();
      }
   }
}

O exemplo a seguir verifica se o Finalize método é chamado quando um objeto que substitui Finalize é destruído. Observe que, em um aplicativo de produção, o Finalize método deve ser substituído para liberar recursos não gerenciados mantidos pelo objeto. Observe também que o exemplo c# fornece um destruidor em vez de substituir o 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 M:System.Object.Finalize method, see the M:System.GC.SuppressFinalize(System.Object) method.

Plataforma Universal do Windows
Disponível desde 8
.NET Framework
Disponível desde 1.1
Biblioteca de Classes Portátil
Com suporte no: plataformas portáteis do .NET
Silverlight
Disponível desde 2.0
Windows Phone Silverlight
Disponível desde 7.0
Windows Phone
Disponível desde 8.1
Retornar ao início
Mostrar: