Esporta (0) Stampa
Espandi tutto
Il presente articolo è stato tradotto automaticamente. Passare il puntatore sulle frasi nell'articolo per visualizzare il testo originale. Ulteriori informazioni.
Traduzione
Originale

Metodo Object.Finalize

Consente a un oggetto di provare a liberare risorse ed eseguire altre operazioni di pulizia prima che l'oggetto stesso venga reclamato dalla procedura di Garbage Collection.

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

protected virtual void Finalize()

Il metodo di Finalize viene utilizzato per eseguire operazioni di pulitura sulle risorse non gestite utilizzate dall'oggetto corrente prima che venga eliminato. Il metodo è protetto, pertanto è accessibile soltanto attraverso questa classe o una classe derivata.

Contenuto della sezione:

Il funzionamento di finalizzazione

La classe di Object non fornisce un'implementazione per il metodo di Finalize e il Garbage Collector non contrassegna i tipi derivati da Object per la finalizzazione a meno che esegue l'override del metodo di Finalize.

Se un tipo eseguire l'override del metodo di Finalize, il Garbage Collector viene aggiunta una voce per ogni istanza del tipo a una struttura interna denominata coda di finalizzazione. La coda di finalizzazione contiene voci per tutti gli oggetti nell'heap gestito di esecuzione del codice di finalizzazione deve eseguire prima che il Garbage Collector sia in grado di recuperare la memoria. Il Garbage Collector chiama quindi il metodo di Finalize automaticamente nelle seguenti circostanze:

  • Dopo che un oggetto diventa accessibile, a meno che l'oggetto sia stato esentato dalla finalizzazione da una chiamata al metodo di GC.SuppressFinalize.

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

Finalize automaticamente viene chiamato una volta su un'istanza specificata, a meno che l'oggetto non sia registrato utilizzando un meccanismo come GC.ReRegisterForFinalize e il metodo di GC.SuppressFinalize avanti non è stata chiamata.

Le operazioni di Finalize hanno i seguenti limiti:

  • Non è definito il momento esatto in cui viene eseguito il finalizzatore durante la procedura di Garbage Collection. Per garantire la versione deterministica delle risorse per le istanze della classe, implementare un metodo di Close o fornire un'implementazione di IDisposable.Dispose.

  • Non è certo che i finalizzatori di due oggetti vengano eseguiti in un ordine specifico, anche se un oggetto fa riferimento all'altro. Ovvero se l'oggetto A include un riferimento a un oggetto B e dispongono di finalizzatori, l'oggetto B già finalizzazione quando il finalizzatore di oggetto All'avvio.

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

Il metodo di Finalize potrebbe non funzionare dopo il completamento o potrebbe non funzionare affatto in condizioni eccezionali seguenti:

  • Se gli altri blocchi del tempo (immette ciclo infinito, tenta di ottenere un blocco che non può ottenere mai, e così via). Poiché il runtime tenta di eseguire i finalizzatori dopo il completamento, altri finalizzatori non possono essere chiamati se un finalizzatore blocca infinito.

  • Se il processo terminerà senza fornire al runtime una probabilità pulire. In questo caso, la prima notifica di completamento del processo effettuata dal runtime è una notifica DLL_PROCESS_DETACH.

Il runtime continua a finalizzare gli 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 ospitate da un'applicazione che esegue l'override dei criteri predefiniti, il runtime termina il processo e non try/blocchi o finalizzatore attivi difinally vengono eseguiti. Questo comportamento garantisce l'integrità del processo qualora il finalizzatore non possa liberare o distruggere risorse.

Note per gli implementatori

È necessario eseguire l'override di Finalize per una classe che utilizza risorse non gestite come handle di file o connessioni di database che devono essere rilasciati quando l'oggetto gestito che li utilizzano viene rimosso durante un'operazione di Garbage Collection.

Nota importanteImportante

Se un oggetto di SafeHandle è disponibile che va a capo alla risorsa non gestita, si consiglia di implementare il modello dispose con handles e non override sicure Finalize. Per ulteriori informazioni, vedere la sezione di L'alternativa SafeHandle.

Il metodo di Object.Finalize non esegue alcuna operazione per impostazione predefinita, ma è necessario eseguire l'override di Finalize solo se necessario e rilasciare le sole risorse non gestite. Recuperare memoria durante un'operazione di Garbage Collection consente di richiedere molto più tempo se un'operazione di finalizzazione viene eseguita, poiché richiede almeno due Garbage Collection. Inoltre, è necessario eseguire l'override del metodo di Finalize solo per i tipi di riferimento. Common Language Runtime completa solo tipi di riferimento. Ignora i finalizzatori i tipi di valore.

Ogni implementazione di Finalize in un tipo derivato deve chiamare la propria implementazione di Finalize del tipo di base. Questo è l'unico caso in cui il codice dell'applicazione può chiamare il metodo Finalize.

NotaNota

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

Visual C++ fornisce una sintassi specifica per l'implementazione del metodo di Finalize. Per ulteriori informazioni, vedere la sezione "finalizzatori e distruttori" di Procedura: Creazione di istanze delle classi e gli struct.

Poiché il Garbage Collection è non deterministico, non sapere precisamente quando il Garbage Collector esegue la finalizzazione. Per rilasciare subito le risorse, è anche possibile scegliere per implementare eliminare il modello e l'interfaccia IDisposable. L'implementazione di IDisposable.Dispose può essere chiamata dai consumer della classe per liberare le risorse non gestite che è possibile utilizzare il metodo di Finalize per liberare le risorse gestite nel caso in cui il metodo di Dispose non venga chiamato.

Finalize può accettare quasi tutte le azioni, inclusa resuscitare un oggetto ovvero rendere l'oggetto accessibile ancora) dopo che è stato pulito durante un'operazione di Garbage Collection. L'oggetto può, tuttavia, essere ripristinato soltanto una volta; Finalize non può essere chiamato su oggetti ripristinati durante la procedura di Garbage Collection. Esistono un provvedimento che l'implementazione di Finalize non deve essere mai: non deve mai generare un'eccezione.

Alternativa SafeHandle

Creare i finalizzatori affidabili è spesso difficile, poiché non è possibile apportare supposizione sullo stato dell'applicazione e poiché le eccezioni non gestite di sistema come OutOfMemoryException e StackOverflowException terminano il finalizzatore. Anziché implementare un finalizzatore della classe rilasciare le risorse non gestite, è possibile utilizzare un oggetto derivato dalla classe di System.Runtime.InteropServices.SafeHandle per eseguire il wrapping delle risorse non gestite e quindi applicare il modello di eliminazione senza un finalizzatore. .NET Framework fornisce le classi nello spazio dei nomi di Microsoft.Win32 derivate da System.Runtime.InteropServices.SafeHandle:

Nell'esempio seguente viene utilizzato eliminare il modello con safe handles anziché eseguire l'override del metodo di Finalize. Definisce una classe di FileAssociation che esegue il wrapping delle informazioni del Registro di sistema sull'applicazione che gestisce i file con un'estensione di file. Le due handle del Registro di sistema restituite come parametri di out da chiamate RegOpenKeyEx di funzioni Windows vengono passate al costruttore di SafeRegistryHandle. Il metodo protetto di Dispose del tipo chiama quindi il metodo di SafeRegistryHandle.Dispose per liberare queste due punti.


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 si verifica che venga chiamato il metodo Finalize quando viene eliminato un oggetto che esegue l'override di Finalize. Si noti che, in un'applicazione di produzione, l'override del metodo Finalize verrebbe eseguito per rilasciare risorse non gestite mantenute dall'oggetto. Si noti inoltre che nell'esempio C# viene fornito un distruttore e non viene eseguito l'override del metodo Finalize.


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


Per un altro esempio che esegue l'override del metodo di Finalize, vedere il metodo di GC.SuppressFinalize.

.NET Framework

Supportato in: 4.5.2, 4.5.1, 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0

.NET Framework Client Profile

Supportato in: 4, 3.5 SP1

Libreria di classi portabile

Supportato in: Libreria di classi portabile

.NET per applicazioni Windows Store

Supportato in: Windows 8

.NET per applicazioni Windows Phone

Supportato in: Windows Phone 8, Silverlight 8.1

Windows Phone 8.1, Windows Phone 8, Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, Windows Vista SP2, Windows Server 2008 (ruoli di base del server non supportati), Windows Server 2008 R2 (ruoli di base del server supportati con SP1 o versione successiva, Itanium non supportato)

.NET Framework non supporta tutte le versioni di ciascuna piattaforma. Per un elenco delle versioni supportate, vedere Requisiti di sistema di .NET Framework.

Aggiunte alla community

AGGIUNGI
Mostra:
© 2014 Microsoft