Tento článek byl přeložený strojově. Pokud chcete zobrazit článek v angličtině, zaškrtněte políčko Angličtina. Anglickou verzi článku můžete také zobrazit v místním okně přesunutím ukazatele myši nad text.
Překlad
Angličtina

Metoda Object.Finalize ()

.NET Framework (current version)
 

Umožňuje objektu pokusit se uvolnit prostředky a provést další operace vyčištění předtím, než je odstraněn při uvolňování paměti.

Obor názvů:   System
Sestavení:  mscorlib (v mscorlib.dll)

protected virtual void Finalize()

Finalize Metoda se používá k provedení operace čištění nespravované prostředky držené aktuální objekt předtím, než je objekt zničen. Metoda je chráněn a proto je dostupné pouze prostřednictvím této třídy nebo prostřednictvím odvozené třídy.

V této části:

Object Třída poskytuje implementaci pro Finalize Metoda a uvolňování neoznačí typy odvozené z Object k dokončení Pokud přepisují Finalize Metoda.

Pokud typ přepsání Finalize Metoda, uvolňování přidá položku pro každou instanci typu vnitřní struktury nazvané dokončovací fronty. Dokončovací fronta obsahuje záznamy pro všechny objekty ve spravované haldě, jejichž dokončovací kód musí být spuštěn před systému uvolňování paměti může jejich paměť uvolnit. Pak zavolá systému uvolňování paměti Finalize Metoda automaticky za následujících podmínek:

  • Po systému uvolňování paměti zjistil, že objekt je nedostupný, pokud objekt má byly vyloučené z dokončovací voláním GC.SuppressFinalize Metoda.

  • Během vypnutí domény aplikace Pokud je objekt ze dokončovací vyloučený. Během vypnutí dokonce i objekty, které jsou stále k dispozici jsou dokončeny.

Finalize je automaticky volána pouze jednou v dané instance, není-li objekt je znovu zaregistrovat pomocí mechanismus GC.ReRegisterForFinalize a GC.SuppressFinalize následně nebyla volána metoda.

Finalize operace mají následující omezení:

  • Přesný čas, kdy finalizační metoda provádí není definován. K zajištění deterministické uvolnění prostředků pro implementaci instance třídy, Close Metoda nebo zadejte IDisposable.Dispose implementace.

  • Finalizační metody dvou objektů není zaručeno, spustit v libovolném pořadí konkrétní i v případě, že jeden objekt odkazuje na druhý. To znamená pokud objekt A obsahuje odkaz na objekt B a obě mají finalizační metody, objekt B může mít již byl dokončen. při spuštění finalizační metody objektu A.

  • Vlákno, na kterém běží finalizační metoda neurčená.

Finalize Metody nemusí být možné spustit až do ukončení nebo nemusí být možné spustit ve všech následujících výjimečných případech:

  • Pokud jiné finalizační metodu blokuje po neomezenou dobu (přejde do nekonečné smyčky, pokusí se získat zámek ji můžete nikdy získat a tak dále). Vzhledem k tomu, že modul runtime se pokusí spustit finalizační metody k dokončení, ostatní finalizační metody nemusí volána, pokud finalizační metodu bloky po neomezenou dobu.

  • Pokud proces ukončí bez ztráty modul runtime příležitost pro vyčištění. V tomto případě je modul runtime první oznámení o ukončení procesu DLL_PROCESS_DETACH oznámení.

Modul runtime bude nadále finalize objekty během vypnutí pouze tehdy, když počet dokončitelné objekty nadále snížit.

Pokud Finalize nebo přepsání Finalize vyvolává výjimku a modul runtime není hostitelem aplikace, která přepisuje výchozí zásady, modul runtime ukončí proces a žádné aktivní trynebofinally bloky nebo finalizační metody jsou vykonány. Toto chování zajišťuje integritu procesu Pokud finalizační metoda nelze uvolnit nebo zničit prostředky.

Byste měli přepsat Finalize pro třídu, která používá nespravované prostředky, jako soubor popisovače nebo připojení, které musí být uvolněny, když je během uvolňování paměti zrušeny spravovaný objekt, který je používá k databázi.

System_CAPS_importantDůležité

Pokud SafeHandle objekt je k dispozici která obtéká nespravovaný prostředek, Doporučenou alternativou je implementovat vzor dispose s bezpečný popisovač a nemůže přepsat Finalize. Další informace naleznete v tématu alternativní The SafeHandle oddílu.

Object.Finalize Metoda nemá žádný účinek ve výchozím nastavení, ale byste měli přepsat Finalize pouze v případě potřeby a pouze pro uvolnění nespravovaných prostředků. Opětovné získání paměti obvykle trvá déle, pokud Dokončovací operace spuštěna, protože vyžaduje alespoň dvě kolekce uvolňování paměti. Kromě toho byste měli přepsat Finalize metodu pro referenční typy pouze. Modul common language runtime dokončí pouze typy odkazů. Ignoruje finalizační metody na typy hodnot.

Každý provádění Finalize v odvozeném typu, musí volat implementaci jeho základní typ Finalize. To platí pouze v aplikaci, která kód může volat Finalize.

System_CAPS_notePoznámka

Kompilátor jazyka C# neumožňuje přepsat Finalize Metoda. Místo toho poskytnete finalizační metody implementací destruktor pro třídu. Destruktor C# automaticky volá destruktor základní třídy.

Visual C++ také poskytuje svou vlastní syntaxi pro implementaci Finalize Metoda. Další informace naleznete v oddílu "Destruktory a finalizační metody" Postupy: definování a používání tříd a struktur (C++-CLI).

Uvolňování paměti je Nedeterministický, a proto neznáte přesně při uvolňování paměti provádí dokončovací. Pro uvolnění prostředků okamžitě, můžete také provádět vzor dispose a IDisposable rozhraní. IDisposable.Dispose Implementace mohou být volány spotřebitelů vaší třídy uvolnění nespravovaných prostředků a můžete použít Finalize Metoda uvolnění nespravovaných prostředků v případě, že Dispose není zavolána metoda.

Finalize poté, co má byla vyčištěna během uvolňování paměti, může trvat téměř všechny akce, včetně resurrecting objekt (který je, zpřístupnění objekt znovu). Nicméně objekt lze pouze být obnovených jednou; Finalize nelze volat u objektů obnovených během uvolňování paměti. Existuje jedna akce, implementace Finalize by mělo být nikdy: by nikdy nevyvolají výjimku.

Vytvoření spolehlivého finalizační metody je často obtížné, proto nelze provádět předpoklady týkající se stavu aplikace a proto neošetřených výjimek systému, jako OutOfMemoryException a StackOverflowException Ukončit finalizační metoda. Namísto implementace finalizační metody pro třídu k uvolnění nespravovaných prostředků, můžete použít objekt, který je odvozen z System.Runtime.InteropServices.SafeHandle tříd pro obtékání nespravovaných prostředků a potom implementaci vzoru dispose bez finalizační metody. Poskytuje následující třídy v rozhraní .NET Framework Microsoft.Win32 obor názvů, které jsou odvozeny z System.Runtime.InteropServices.SafeHandle:

Následující příklad používá vzor dispose s bezpečné popisovače namísto přepsání Finalize Metoda. Definuje FileAssociation Třída, která obaluje registru informace o aplikaci, která zpracovává soubory s příponou určitý soubor. Popisovače dva registru vrácena jako out Parametry systémem Windows RegOpenKeyEx volání funkce jsou předány SafeRegistryHandle konstruktor. Typ je chráněn Dispose poté volá metodu SafeRegistryHandle.Dispose Metoda uvolnit tyto dva popisovače.

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

V následujícím příkladu ověřuje, že Finalize Metoda je volána, když objekt, který přepíše Finalize zničen. Všimněte si, že se v aplikaci výroby Finalize Metoda by přepsat uvolnit nespravované prostředky držené objektem. Všimněte si také, že poskytuje příklad jazyka C# destruktor namísto přepsání Finalize Metoda.

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.

Univerzální platforma Windows
K dispozici od 8
.NET Framework
K dispozici od 1.1
Přenosná knihovna tříd
Podporováno v: přenosné platformy .NET
Silverlight
K dispozici od 2.0
Windows Phone Silverlight
K dispozici od 7.0
Windows Phone
K dispozici od 8.1
Zpět na začátek
Zobrazit: