Questo articolo è stato tradotto automaticamente. Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

Metodo Object.Finalize ()

 

Data di pubblicazione: ottobre 2016

Consente a un oggetto di effettuare un tentativo di liberare risorse ed eseguire altre operazioni di pulizia prima che venga recuperato da Garbage Collection.

Spazio dei nomi:   System
Assembly:  mscorlib (in mscorlib.dll)

protected virtual void Finalize()

Il Finalize metodo viene utilizzato per eseguire operazioni di pulitura su risorse non gestite bloccate dall'oggetto corrente prima che l'oggetto viene eliminato definitivamente. Il metodo è protetto e pertanto è accessibile solo tramite questa classe o una classe derivata.

Contenuto della sezione:

Il Object classe non fornisce alcuna implementazione per il Finalize metodo e il garbage collector non contrassegnare i tipi derivati da Object per la finalizzazione a meno che non hanno la precedenza il Finalize metodo.

Se un tipo esegue l'override di Finalize (metodo), il garbage collector aggiunge una voce per ogni istanza del tipo a una struttura interna denominata coda di finalizzazione. Coda di finalizzazione contiene voci per tutti gli oggetti nell'heap gestito, il cui codice la finalizzazione deve essere eseguito prima che il garbage collector di recuperare la memoria. Il garbage collector chiama quindi il Finalize metodo automaticamente le seguenti condizioni:

  • Dopo che il garbage collector ha individuato un oggetto non è accessibile, a meno che l'oggetto sia stato esonerato dalla finalizzazione da una chiamata al GC.SuppressFinalize metodo.

  • Durante l'arresto di un dominio applicazione, a meno che l'oggetto è esente dalla finalizzazione. Durante l'arresto, anche gli oggetti che sono ancora accessibili vengono finalizzati.

Finalizeviene chiamato automaticamente una sola volta in un'istanza specifica, a meno che l'oggetto è nuovamente registrato con un meccanismo, ad esempio GC.ReRegisterForFinalize e GC.SuppressFinalize metodo non è stato chiamato in seguito.

Finalizele operazioni presentano le limitazioni seguenti:

  • L'ora esatta in cui viene eseguito il finalizzatore è definito. Per garantire il rilascio deterministico delle risorse per le istanze della classe, implementare un Close metodo o fornire un IDisposable.Dispose implementazione.

  • I finalizzatori di due oggetti non sono garantiti per l'esecuzione in un ordine specifico, anche se un oggetto fa riferimento a altro. Ovvero, se l'oggetto ha un riferimento all'oggetto B e prevedono i finalizzatori, oggetto B potrebbe sia già stato completato quando viene avviato il finalizzatore dell'oggetto.

  • Il thread in cui viene eseguito il finalizzatore non è specificato.

Il Finalize metodo potrebbe non essere eseguito fino al completamento o potrebbe non essere eseguito affatto eccezionali circostanze seguenti:

  • Se un altro finalizzatore in modo indefinito (consente di spostarsi in un ciclo infinito, tenta di ottenere un blocco non può ottenere e così via). Poiché il runtime tenta di eseguire i finalizzatori fino al completamento, gli altri finalizzatori potrebbero non essere chiamate se un finalizzatore è bloccato per un periodo illimitato.

  • Se il processo viene terminato senza consentirà di pulire il runtime. In questo caso, prima notifica di completamento del processo del runtime è una notifica DLL_PROCESS_DETACH.

Il runtime continua a finalizzazione degli oggetti durante l'arresto solo quando il numero di oggetti finalizzabili continua a diminuire.

Se Finalize o un override di Finalize genera un'eccezione e il runtime non è ospitata da un'applicazione che sostituisce il criterio predefinito, il runtime termina il processo e nessun blocco try/finally vengono eseguiti i blocchi o i finalizzatori. Questo comportamento assicura l'integrità del processo se il finalizzatore non può liberare o distruggere risorse.

È necessario eseguire l'override Finalize per una classe che utilizza le risorse non gestite, ad esempio gli handle di file o connessioni di database che devono essere liberate quando viene eliminato l'oggetto gestito in cui vengono utilizzati durante l'operazione di garbage collection.

System_CAPS_importantImportante

Se un SafeHandle l'oggetto è disponibile che esegue il wrapping della risorsa non gestita, l'alternativa consigliata consiste nell'implementare il modello dispose un handle sicuro e non eseguire l'override Finalize. Per ulteriori informazioni, vedere alternativa SafeHandle il sezione.

Il Object.Finalize metodo non esegue alcuna operazione per impostazione predefinita, ma è necessario eseguire l'override Finalize solo se necessario e solo per rilasciare le risorse non gestite. Il recupero della memoria tende a durare più a lungo se viene eseguita un'operazione di completamento, perché richiede almeno due operazioni di garbage collection. Inoltre, è necessario eseguire l'override di Finalize solo i tipi di metodo per riferimento. Common language runtime consente di finalizzare solo i tipi di riferimento. Ignora i finalizzatori sui tipi di valore.

Ogni implementazione di Finalize in un tipo derivato deve chiamare l'implementazione del tipo di base di Finalize. Questo è l'unico caso in cui applicazione è possibile chiamare codice Finalize.

System_CAPS_noteNota

Il compilatore c# non consente di eseguire l'override di Finalize metodo. Al contrario, si fornisce un finalizzatore implementando un distruttore per la classe. Un distruttore c# chiama automaticamente il distruttore della relativa classe base.

Visual C++ fornisce anche una sintassi specifica per l'implementazione di Finalize metodo. Per ulteriori informazioni, vedere la sezione "Distruttori e finalizzatori" di Procedura: definire e utilizzare classi e struct (C++ /CLI).

Poiché l'operazione di garbage collection è non deterministico, non si conoscono con precisione durante la finalizzazione effettuata dal garbage collector. Per rilasciare le risorse immediatamente, è possibile anche scegliere di implementare il modello dispose e IDisposable interfaccia. Il IDisposable.Dispose implementazione può essere chiamata dal consumer della classe per liberare risorse non gestite e, è possibile utilizzare il Finalize metodo per liberare risorse non gestite nel caso in cui il Dispose non viene chiamato.

Finalizepuò richiedere qualsiasi azione, tra cui ripristinare un oggetto (che è, renderlo accessibile nuovo) dopo averlo eliminato durante l'operazione di garbage collection. Tuttavia, l'oggetto può essere ripristinato soltanto una volta. Finalize non può essere chiamato su oggetti ripristinati durante l'operazione di garbage collection. È un'azione che l'implementazione di Finalize deve non accettano mai: non deve mai generare un'eccezione.

Creazione di finalizzatori affidabili è spesso difficile, poiché è possibile basarsi su presupposti sullo stato dell'applicazione e sistema eccezioni non gestite, ad esempio OutOfMemoryException e StackOverflowException terminare il finalizzatore. Anziché implementare un finalizzatore per la classe per rilasciare le risorse non gestite, è possibile utilizzare un oggetto derivato dalla System.Runtime.InteropServices.SafeHandle classe per eseguire il wrapping delle risorse non gestite e quindi implementare il modello dispose senza un finalizzatore. .NET Framework fornisce le seguenti classi di Microsoft.Win32 dello spazio dei nomi che derivano da System.Runtime.InteropServices.SafeHandle:

L'esempio seguente usa il modello dispose con handle sicuri anziché eseguire l'override di Finalize metodo. Definisce un FileAssociation classe che esegue il wrapping delle informazioni del Registro di sistema sull'applicazione che gestisce i file con un'estensione di file specifico. Gli handle del Registro di sistema restituiti come out parametri da Windows RegOpenKeyEx chiamate di funzione vengono passate al SafeRegistryHandle costruttore. Il tipo del protetto Dispose chiama quindi il SafeRegistryHandle.Dispose metodo per liberare gli handle di due.

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

Nell'esempio seguente verifica che il Finalize metodo viene chiamato quando un oggetto che esegue l'override Finalize viene eliminato definitivamente. Si noti che, in un'applicazione di produzione di Finalize potrebbe eseguire l'override di metodo per rilasciare le risorse non gestite utilizzate dall'oggetto. Si noti inoltre che l'esempio c# fornisce un distruttore anziché eseguire l'override di Finalize metodo.

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.

Universal Windows Platform
Disponibile da 8
.NET Framework
Disponibile da 1.1
Libreria di classi portabile
Supportato in: piattaforme .NET portabili
Silverlight
Disponibile da 2.0
Windows Phone Silverlight
Disponibile da 7.0
Windows Phone
Disponibile da 8.1
Torna all'inizio
Mostra: