Экспорт (0) Печать
Развернуть все
Данная статья переведена автоматически. Наведите указатель мыши на предложения статьи, чтобы просмотреть исходный текст. Дополнительные сведения.
Перевод
Текст оригинала

Object.Finalize - метод

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

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

protected virtual void Finalize()

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

В данном разделе:

После завершения работы

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

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

Важное примечаниеВажно

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

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

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

ПримечаниеПримечание

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

C Visual C++ также предоставляет свой собственный синтаксис для реализации метода Finalize. Дополнительные сведения см. в разделе «и деструкторов завершений» Как Классы и структуры создания экземпляра.

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

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

Альтернативный вариант с использованием SafeHandle

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

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


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


Для дополнительный образец, который переопределяет метод Finalize см. в описании метода GC.SuppressFinalize.

.NET Framework

Поддерживается в версиях: 4.5.2, 4.5.1, 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0

.NET Framework (клиентский профиль)

Поддерживается в версиях: 4, 3.5 с пакетом обновления 1 (SP1)

Переносимая библиотека классов

Поддерживается в версии: Переносимая библиотека классов

Приложения .NET для Магазина Windows

Поддерживается в версии: Windows 8

Приложения .NET для Windows Phone

Поддерживается в версиях: 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 с пакетом обновления 2 (SP2), Windows Server 2008 (роль основных серверных компонентов не поддерживается), Windows Server 2008 R2 (роль основных серверных компонентов поддерживается в пакете обновления 1 (SP1) или выше; системы на базе Itanium не поддерживаются)

.NET Framework поддерживает не все версии каждой платформы. Поддерживаемые версии перечислены в разделе Требования к системе для .NET Framework.

Добавления сообщества

ДОБАВИТЬ
Показ:
© 2015 Microsoft