Exporter (0) Imprimer
Développer tout
Cet article a fait l'objet d'une traduction automatique. Déplacez votre pointeur sur les phrases de l'article pour voir la version originale de ce texte. Informations supplémentaires.
Traduction
Source

Object.Finalize, méthode

Autorise un objet à tenter de libérer des ressources et d'exécuter d'autres opérations de nettoyage avant qu'il ne soit récupéré par l'opération garbage collection.

Espace de noms :  System
Assembly :  mscorlib (dans mscorlib.dll)

protected virtual void Finalize()

La méthode d'Finalize permet d'exécuter l'opération de nettoyage sur les ressources non managées gérées par l'objet actuel avant que l'objet est détruit. La méthode est protégée et n'est donc accessible qu'à l'aide de cette classe ou d'une classe dérivée.

Dans cette section :

Comment la finalisation de l'exécution

La classe d'Object ne fournit une implémentation pour la méthode d'Finalize, et le garbage collector ne signale pas les types dérivés d'Object de la finalisation à moins qu'elles remplacent la méthode d'Finalize.

Si un type substitue la méthode de Finalize, le garbage collector ajoute une entrée pour chaque instance du type dans une structure interne appelée la file d'attente de finalisation. La file d'attente de finalisation contient des entrées pour tous les objets du segment de mémoire managé du code de finalisation doit s'exécuter avant que le garbage collector peut libérer sa mémoire. Le garbage collector appelle la méthode d'Finalize automatiquement dans les conditions suivantes :

  • Une fois qu'un objet devienne inaccessible, à moins que l'objet a été exempté de la finalisation par un appel à la méthode d'GC.SuppressFinalize.

  • Pendant l'arrêt d'une instruction SCOPE, à moins que l'objet soit exempt de la finalisation. Pendant l'arrêt, même les objets qui sont toujours activées sont finalisés.

Finalize est appelé automatiquement une seule fois sur une instance donnée, à moins que l'objet nouveau enregistré à l'aide d'un mécanisme par exemple GC.ReRegisterForFinalize et la méthode d'GC.SuppressFinalize n'a pas été appelée ensuite.

Les opérations Finalize possèdent les restrictions suivantes :

  • L'heure exacte à laquelle le finaliseur s'exécute pendant l'opération garbage collection n'est pas définie. Pour vérifier la version déterministe des ressources pour les instances de la classe, implémentez une méthode d'Close ou fournir une implémentation d'IDisposable.Dispose.

  • Il n'est pas garanti que les finaliseurs de deux objets s'exécuteront dans un ordre déterminé, même si un objet fait référence à l'autre. Autrement dit, si l'objet A une référence à l'objet B et les deux arguments reçoivent les finaliseurs, l'objet B peut avoir déjà été finalisé lorsque le finaliseur de le démarrage de l'objet A.

  • Le thread sur lequel le finaliseur s'exécute pas spécifié.

La méthode d'Finalize peut ne pas fonctionner à le bout ou ne peut pas exécuter du tout dans les circonstances exceptionnelles suivantes :

  • Si un finaliseur se fige indéfiniment (entre dans une boucle infinie, tente d'obtenir un verrou qu'il ne peut jamais commencer, etc.). Étant donné que essaie d'exécution pour exécuter les finaliseurs à l'achèvement, les finaliseurs ne peuvent pas être appelées si un finaliseur se fige indéfiniment.

  • Si le processus se termine sans donner au runtime une occasion de nettoyer. Dans ce cas, la première notification de l'achèvement du processus du runtime est une notification DLL_PROCESS_DETACH.

Au moment de l'exécution continue à finaliser les objets durant l'arrêt uniquement lorsque le nombre d'objets finalisables continue à réduire.

Si Finalize ou une substitution de Finalize lève une exception, et le runtime n'est pas hébergé par une application qui remplace la stratégie par défaut, l'exécution s'arrête le processus et aucun tryactif/finally ne se bloque ou les finaliseurs sont exécutés. Ce comportement garantit l'intégrité du processus si le finaliseur ne peut pas libérer ou détruire des ressources.

Remarques pour les implémenteurs

Vous devez remplacer Finalize d'une classe qui utilise les ressources gérées comme les descripteurs de fichiers ou les connexions de base de données qui doivent être libérées à l'objet managé qui utilise est ignoré pendant le garbage collection.

Remarque importanteImportant

Si un objet d'SafeHandle est disponible que les enveloppes votre ressources non managées, l'autre est recommandée pour implémenter le modèle de préparer avec un handle sécurisé et non une substitution Finalize. Pour plus d'informations, consultez la section " L'alternative au SafeHandle.

La méthode d'Object.Finalize n'a aucun effet par défaut, mais vous devez remplacer Finalize uniquement si nécessaire, et libérer uniquement les ressources managées. Libération de la mémoire pendant le garbage collection a tendance à prendre beaucoup plus de temps si une opération de finalisation de l'exécution, car il requiert au moins deux garbages collection. En outre, vous devez remplacer la méthode d'Finalize pour les types référence uniquement. Le common langage runtime finalise uniquement les types référence. Il ignore les finaliseurs sur les types de valeur.

Toutes les implémentations de Finalize dans un type dérivé doivent appeler l'implémentation de Finalize de leur type de base. Il s'agit du seul cas où le code d'application est autorisé à appeler Finalize.

RemarqueRemarque

Le compilateur c ne vous permet pas de remplacer la méthode d'Finalize. À la place, vous fournissez un finaliseur en implémentant destructeur pour votre classe. Un destructeur C# appelle automatiquement le destructeur de la classe de base.

Visual C++ fournit également sa propre syntaxe d'implémentation de la méthode d'Finalize. Pour plus d'informations, consultez la section « destructeurs et de finaliseurs » Comment : Classes et structures d'instancié.

Étant donné que le garbage collection n'est pas déterministe, vous ne savez pas précisément lorsque le garbage collector exécute la finalisation. Pour libérer des ressources immédiatement, vous pouvez également choisir d'implémenter supprimez le modèle et l'interface d'IDisposable. L'implémentation d'IDisposable.Dispose peut pas être appelée par les consommateurs de la classe pour libérer les ressources managées, et vous pouvez utiliser la méthode de Finalize pour libérer les ressources managées au cas où la méthode d'Dispose n'est pas appelé.

Finalize peut effectuer presque n'importe quelle mesure, ni ressusciter objet (autrement dit, faisant l'objet de nouveau disponible) après avoir été nettoyé pendant le garbage collection. Cependant, l'objet ne peut être ressuscité qu'une seule fois. Finalize ne peut pas être appelé sur des objets ressuscités pendant une opération garbage collection. Il existe une mesure que l'implémentation de Finalize ne doit jamais être : il ne doit jamais lever d'exception.

L'alternative de SafeHandle

Créer les finaliseurs fiables est souvent difficile, car vous ne pouvez pas faire d'hypothèses concernant l'état de votre application, comme les exceptions non gérées système telles que OutOfMemoryException et l'StackOverflowException terminent le finaliseur. Au lieu d'implémenter un finaliseur pour votre classe libère les ressources non managées, vous pouvez utiliser un objet dérivé de la classe d'System.Runtime.InteropServices.SafeHandle pour encapsuler les ressources non managées, puis implémenter le modèle de préparer sans finaliseur. .NET Framework fournit des classes suivantes dans l'espace de noms de Microsoft.Win32 dérivés d'System.Runtime.InteropServices.SafeHandle:

L'exemple suivant utilise supprimez le modèle avec les descripteurs de sécurité au lieu de remplacer la méthode d'Finalize. Il définit une classe de FileAssociation qui encapsule les informations de Registre sur l'application qui traite les fichiers portant l'extension de fichier spécifique. Les deux handles de Registre retournés sous la forme de paramètres d'out par des RegOpenKeyEx appels de fonction Windows passés au constructeur d'SafeRegistryHandle. La méthode est d'Dispose de type appelle la méthode d'SafeRegistryHandle.Dispose pour libérer les deux poignées.


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


L'exemple suivant vérifie que la méthode Finalize est appelée lorsqu'un objet qui substitue Finalize est détruit. Notez que, dans une application de production, la méthode Finalize est substituée pour libérer des ressources non managées retenues par l'objet. Notez également que l'exemple de code C# fournit un destructeur au lieu de substituer la méthode 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


Pour un exemple supplémentaire qui substitue la méthode de Finalize, consultez la méthode d'GC.SuppressFinalize.

.NET Framework

Pris en charge dans : 4.5.2, 4.5.1, 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0

.NET Framework Client Profile

Pris en charge dans : 4, 3.5 SP1

Bibliothèque de classes portable

Pris en charge dans : Bibliothèque de classes portable

.NET pour les applications du Windows Store

Pris en charge dans : Windows 8

.NET pour les applications Windows Phone

Pris en charge dans : 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 (rôle principal du serveur non pris en charge), Windows Server 2008 R2 (rôle principal du serveur pris en charge avec SP1 ou version ultérieure ; Itanium non pris en charge)

Le .NET Framework ne prend pas en charge toutes les versions de chaque plateforme. Pour obtenir la liste des versions prises en charge, consultez Configuration requise du .NET Framework.

Ajouts de la communauté

AJOUTER
Afficher:
© 2014 Microsoft