Cet article a fait l’objet d’une traduction automatique. Pour afficher l’article en anglais, activez la case d’option Anglais. Vous pouvez également afficher le texte anglais dans une fenêtre contextuelle en faisant glisser le pointeur de la souris sur le texte traduit.
Traduction
Anglais

Object.Finalize méthode ()

 

Date de publication : novembre 2016

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

Le Finalize méthode est utilisée pour effectuer des opérations de nettoyage sur les ressources non managées détenues par l’objet actuel avant la destruction de l’objet. La méthode est protégée et par conséquent, est accessible uniquement par le biais de cette classe ou une classe dérivée.

Dans cette section :

Le Object classe ne fournit pas d’implémentation pour la Finalize (méthode) et que le garbage collector ne marque pas les types dérivés de Object pour la finalisation, sauf si elles remplacent les Finalize (méthode).

Si un type remplace le Finalize (méthode), le garbage collector ajoute une entrée pour chaque instance du type à 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 dans le tas managé dont le code de la finalisation doit s’exécuter avant que le garbage collector puisse récupérer la mémoire. Le garbage collector appelle ensuite la Finalize méthode automatiquement dans les conditions suivantes :

  • Une fois que le garbage collector a découvert qu’un objet est inaccessible, à moins que l’objet a été dispensé de finalisation par un appel à la GC.SuppressFinalize (méthode).

  • Pendant l’arrêt d’un domaine d’application, sauf si l’objet est exempté de la finalisation. Lors de l’arrêt, même les objets qui sont encore accessibles finalisées.

Finalizeest automatiquement appelé qu’une seule fois sur une instance donnée, sauf si l’objet est réinscrit à l’aide d’un mécanisme comme GC.ReRegisterForFinalize et GC.SuppressFinalize (méthode) n’a pas été appelée par la suite.

Finalizeopérations présentent les limitations suivantes :

  • L’heure exacte à laquelle s’exécute le finaliseur n’est pas défini. Pour garantir la libération des ressources pour implémenter des instances de votre classe, un Close méthode ou fournissez un IDisposable.Dispose mise en œuvre.

  • Les finaliseurs de deux objets ne sont pas garanties pour s’exécuter dans un ordre spécifique, 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 possèdent des finaliseurs, l’objet B peut avoir déjà été finalisation lorsque le finaliseur de l’objet A démarre.

  • Le thread sur lequel s’exécute le finaliseur n’est pas spécifié.

Le Finalize méthode ne peut pas s’exécuter jusqu'à son achèvement, ou s’exécute ne peut-être pas du tout dans les circonstances exceptionnelles suivantes :

  • Si un autre finaliseur se bloque indéfiniment (augmentent dans une boucle infinie, essaie d’obtenir un verrou, il peut obtenir jamais et ainsi de suite). Étant donné que le runtime tente d’exécuter des finaliseurs jusqu'à son achèvement, les autres finaliseurs ne pas être appelés si un finaliseur se bloque indéfiniment.

  • Si le processus se termine sans donner au runtime une chance de les nettoyer. Dans ce cas, la première notification d’arrêt du processus du runtime est une notification DLL_PROCESS_DETACH.

Le runtime continue à finaliser des objets pendant l’arrêt aussi longtemps que le nombre d’objets finalisables diminue.

Si Finalize ou une substitution de Finalize lève une exception et que le runtime n’est pas hébergée par une application qui substitue la stratégie par défaut, le runtime termine le processus et aucun active try/finally finaliseurs ou les blocs sont exécutées. Ce comportement garantit l’intégrité du processus si le finaliseur ne peut pas libérer ou détruire des ressources.

Vous devez substituer Finalize pour une classe qui utilise les ressources non managées, telles que les handles de fichiers ou les connexions qui doivent être lancées lorsque l’objet managé qui les utilise est ignoré pendant le garbage collection de base de données.

System_CAPS_importantImportant

Si un SafeHandle objet n’est disponible qui encapsule votre ressource non managée, l’alternative recommandée consiste à implémenter le modèle de suppression avec un handle sécurisé et ne pas substituer Finalize. Pour plus d’informations, consultez alternative de SafeHandle le section.

Le Object.Finalize méthode ne fait rien par défaut, mais vous devez remplacer Finalize uniquement si nécessaire et uniquement pour libérer les ressources non managées. Récupération de mémoire a tendance à s’allonger considérablement si une opération de finalisation est exécutée, car elle nécessite au moins deux opérations garbage collection. En outre, vous devez substituer la Finalize types de méthode pour référence uniquement. Le common language runtime finalise uniquement les types référence. Il ignore les finaliseurs dans les types valeur.

Chaque implémentation de Finalize dans un type dérivé doit appeler mise en œuvre de son type de base de Finalize. C’est le cas uniquement dans l’application le code est autorisé à appeler Finalize.

System_CAPS_noteRemarque

Le compilateur c# n’autorise pas vous permet de remplacer le Finalize (méthode). Au lieu de cela, vous fournissez un finaliseur en implémentant un destructeur pour votre classe. Un destructeur c# appelle automatiquement le destructeur de sa classe de base.

Visual C++ fournit aussi sa propre syntaxe pour l’implémentation de la Finalize (méthode). Pour plus d’informations, consultez la section « Destructeurs et finaliseurs » de Comment : définir et consommer des Classes et Structs (C++-CLI).

Étant donné que le garbage collection est non déterministe, vous ne savez pas précisément à quel moment le garbage collector effectue la finalisation. Pour libérer des ressources immédiatement, vous pouvez également choisir d’implémenter le modèle de suppression et IDisposable interface. Le IDisposable.Dispose implémentation peut être appelée par les consommateurs de votre classe de libérer des ressources non managées, et vous pouvez utiliser la Finalize méthode pour libérer les ressources non managées dans le cas où la Dispose méthode n’est pas appelée.

Finalizepeut effectuer quasiment toute action, y compris ressusciter (un objet qui rendre à nouveau accessible) a été nettoyé pendant le garbage collection. Toutefois, l’objet peut uniquement être réactivé une seule fois ; Finalize ne peut pas être appelée sur des objets ressuscités pendant le garbage collection. Il existe une seule action que votre implémentation de Finalize ne doit jamais prendre : il ne doit jamais lever une exception.

Création des finaliseurs fiables est souvent difficile, car vous ne pouvez pas faire d’hypothèses concernant l’état de votre application et non prises en charge des exceptions de système comme OutOfMemoryException et StackOverflowException terminer le finaliseur. Au lieu d’implémenter un finaliseur pour votre classe pour libérer les ressources non managées, vous pouvez utiliser un objet qui est dérivé de la System.Runtime.InteropServices.SafeHandle classe pour encapsuler les ressources non managées et implémentez le modèle de suppression sans un finaliseur. Le .NET Framework fournit les classes suivantes dans le Microsoft.Win32 espace de noms qui sont dérivés de System.Runtime.InteropServices.SafeHandle:

L’exemple suivant utilise le modèle de suppression avec des handles sécurisés au lieu de remplacer le Finalize (méthode). Il définit un FileAssociation classe qui encapsule des informations du Registre sur l’application qui traite les fichiers avec une extension de fichier particulière. Les handles de deux Registre retournés en tant que out paramètres par Windows RegOpenKeyEx les appels de fonction sont passés à la SafeRegistryHandle constructeur. Le type de protégé Dispose méthode appelle ensuite la SafeRegistryHandle.Dispose méthode pour libérer ces 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 Finalize méthode est appelée lorsqu’un objet qui substitue Finalize est détruit. Notez que, dans une application de production, le Finalize méthode est substituée pour libérer les ressources non managées détenues par l’objet. Notez également que l’exemple c# fournit un destructeur au lieu de remplacer le Finalize (méthode).

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.

Plateforme Windows universelle
Disponible depuis 8
.NET Framework
Disponible depuis 1.1
Bibliothèque de classes portable
Pris en charge dans : plateformes .NET portables
Silverlight
Disponible depuis 2.0
Silverlight pour Windows Phone
Disponible depuis 7.0
Windows Phone
Disponible depuis 8.1
Retour au début
Afficher: