Данная статья переведена с помощью средств машинного перевода. Чтобы просмотреть ее на английском языке, установите флажок Английский. Вы также можете просматривать английский текст во всплывающем окне, наводя указатель мыши на переведенный текст.
Перевод
Английский

Метод Object.Finalize ()

 

Опубликовано: Октябрь 2016

Позволяет объекту попытаться освободить ресурсы и выполнить другие операции по очистке перед тем, как объект будет утилизирован сборщиком мусора.

Пространство имен:   System
Сборка:  mscorlib (в mscorlib.dll)

protected virtual void Finalize()

Finalize Метод используется для выполнения операций очистки неуправляемых ресурсов, удерживаемых текущим объектом до уничтожения объекта. Метод является защищенным и поэтому доступен только через данный класс или производный класс.

Содержание

Object Класс не предоставляет реализацию для Finalize метода и сборщик мусора не помечает типов, производных от Object к завершению, если только они переопределяют Finalize метод.

Если тип переопределяется Finalize метод, сборщик мусора будет добавлена запись для каждого экземпляра типа внутренней структуры, которая называется очередью завершения. Очередь завершения содержит записи для всех объектов в управляемой куче, код завершения необходимо запустить перед сборщик мусора мог освободить память. Сборщик мусора вызывает Finalize метод автоматически при выполнении следующих условий:

  • После сборщик мусора был обнаружен объект недоступен, если объект завершение было отключено путем вызова GC.SuppressFinalize метод.

  • Финализаторы объектов вызываются в неопределенном порядке, даже если один объект ссылается на другой. Во время завершения работы были закрыты даже объекты, которые по-прежнему доступны.

Finalize автоматически вызывается только один раз на данном экземпляре, если объект был заново зарегистрирован с помощью механизма, такие как GC.ReRegisterForFinalize и GC.SuppressFinalize впоследствии не был вызван метод.

Finalize операции имеют следующие ограничения:

  • Точное время выполнения метода завершения не определен. Чтобы обеспечить детерминированного освобождения ресурсов для реализации экземпляры этого класса, Close метод или предоставить IDisposable.Dispose реализации.

  • Не гарантируется выполнение в какой-либо конкретной последовательности методов завершения двух объектов , даже если один объект ссылается на другой. То есть, если в объекте A имеется ссылка на объект B и оба имеют финализаторы, объект B может быть уже был завершен при запуске метода завершения объекта A.

  • Поток, на котором выполняется метод завершения не определен.

Finalize Метод может не запуститься для завершения или может не запуститься вообще в следующих исключительных обстоятельствах:

  • Другой метод завершения осуществляет бесконечную блокировку (образует бесконечный цикл, пытается получить блокировку, которая для него недоступна, и так далее). Так как среда выполнения пытается выполнять финализаторы до завершения, другие методы завершения вызвать нельзя Если финализатор бесконечно.

  • Процесс завершается без предоставления среде выполнения возможности очистки. В этом случае первый уведомлением среды выполнения о завершении процесса будет уведомление DLL_PROCESS_DETACH.

Среда выполнения продолжает завершает объекты во время завершения работы только в том случае, пока число объектов, подлежащих завершению, продолжает уменьшаться.

Если Finalize или переопределение Finalize создает исключение и среда выполнения не размещена в приложение, которое переопределяет политику по умолчанию, среда выполнения завершает процесс и ни один активный tryилиfinally блоки и методы завершения выполняются. Такое поведение гарантирует целостность процесса при невозможности освобождения или удаления ресурсов метод завершения.

Необходимо переопределить Finalize для класса, который использует неуправляемые ресурсы, такие как дескрипторы файлов или подключения, которые должны быть освобождены при отказе использующего их управляемого объекта во время сборки мусора баз данных.

System_CAPS_importantВажно

Если SafeHandle объект доступен, создает оболочку для неуправляемого ресурса, рекомендуется реализовать шаблон dispose с безопасный дескриптор и переопределяет Finalize. Дополнительные сведения см. в разделе SafeHandle альтернатива раздел.

Object.Finalize Метод не выполняет никаких действий по умолчанию, но необходимо переопределить Finalize только в том случае, если необходимо и только для освобождения неуправляемых ресурсов. Освобождение памяти обычно занимает больше времени при выполнении операции завершения, поскольку требуется по крайней мере две сборки мусора. Кроме того, необходимо переопределить Finalize только для типов метод для ссылки. Общеязыковая среда выполнения завершает только ссылочные типы. Он игнорирует методы завершения для типов значений.

Каждая реализация Finalize в производном типе, необходимо вызвать реализацию базового типа Finalize. Это единственный случай, в приложение, в котором код может вызвать Finalize.

System_CAPS_noteПримечание

Компилятор C# не позволяет переопределить Finalize метод. Вместо этого предоставлять метод завершения, реализовав деструктор для класса. Деструктор C# автоматически вызывает деструкторы базового класса.

Visual C++ также предоставляет свой собственный синтаксис для реализации Finalize метод. Для получения дополнительной информации ознакомьтесь с разделом «Деструкторы и методы завершения» Практическое руководство: определение и использование классов и структур (C++-CLI).

Так как сборщик мусора является недетерминированным, неизвестно, когда сборщик мусора выполняет финализации. Для освобождения ресурсов немедленно, можно реализовать шаблон удаления и IDisposable интерфейса. IDisposable.Dispose Реализации могут быть вызваны потребители этого класса, чтобы освободить неуправляемые ресурсы, а также можно использовать Finalize для освобождения неуправляемых ресурсов в случае, если Dispose метод не вызывается.

Finalize После его очистке во время сборки мусора занимает почти любые действия, включая восстановление объекта (т.е. доступности еще раз). Тем не менее объект может быть восстановлен только один раз; Finalize не может вызываться для восстановленных объектов во время сборки мусора. Существует одно действие, реализация Finalize никогда не потребуется: никогда не вызывает исключение.

Создание надежных методов завершения очень сложно, поскольку не может делать предположения о состоянии приложения и необработанные исключения системы, такие как OutOfMemoryException и StackOverflowException Завершение метода завершения. Вместо реализации метода завершения класса для освобождения неуправляемых ресурсов, можно использовать объект, который является производным от System.Runtime.InteropServices.SafeHandle для неуправляемых ресурсов, по словам, а затем реализовать шаблон dispose без метода завершения. Платформа .NET Framework предоставляет следующие классы в Microsoft.Win32 пространства имен, являются производными от System.Runtime.InteropServices.SafeHandle:

  • SafeFileHandle Представляет класс-оболочку для дескриптора файла.

  • SafeMemoryMappedFileHandle Представляет класс-оболочку для дескрипторов файлов, размещенный в памяти.

  • SafeMemoryMappedViewHandle Класс-оболочка для указателя на блок неуправляемой памяти.

  • SafeNCryptKeyHandle, SafeNCryptProviderHandle, и SafeNCryptSecretHandle являются классы-оболочки для криптографических дескрипторов.

  • SafePipeHandle Класс-оболочка для дескрипторов канала.

  • SafeRegistryHandle Представляет класс-оболочку для дескриптора в раздел реестра.

  • SafeWaitHandle Представляет класс-оболочку для дескриптора ожидания.

В следующем примере используется шаблон удаления с безопасные дескрипторы вместо переопределения Finalize метод. Он определяет FileAssociation класс-оболочку реестра сведения о приложении, который обрабатывает файлы с расширением определенного файла. Обрабатывает два реестра, возвращаются в виде out параметров Windows RegOpenKeyEx вызовы функции передаются SafeRegistryHandle конструктор. Защищенный тип Dispose затем вызывает метод SafeRegistryHandle.Dispose для освобождения этих двух дескрипторов.

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

В следующем примере проверяется, Finalize метод вызывается, когда объект, который переопределяет Finalize уничтожается. Обратите внимание, что в рабочем приложении Finalize метод может быть переопределен для освобождать неуправляемые ресурсы, удерживаемые объектом. Также Обратите внимание, что в примере кода C# содержит деструктор вместо переопределения 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

For an additional example that overrides the M:System.Object.Finalize method, see the M:System.GC.SuppressFinalize(System.Object) method.

Универсальная платформа Windows
Доступно с 8
.NET Framework
Доступно с 1.1
Переносимая библиотека классов
Поддерживается в: переносимые платформы .NET
Silverlight
Доступно с 2.0
Windows Phone Silverlight
Доступно с 7.0
Windows Phone
Доступно с 8.1
Вернуться в начало
Показ: