Методы завершения (руководство по программированию в C#)Finalizers (C# Programming Guide)

Методы завершения (также называемые деструкторами) используются для любой необходимой окончательной очистки, когда сборщик мусора окончательно удаляет экземпляра класса.Finalizers (which are also called destructors) are used to perform any necessary final clean-up when a class instance is being collected by the garbage collector.

ПримечанияRemarks

  • В структурах определение методов завершения невозможно.Finalizers cannot be defined in structs. Они применяются только в классах.They are only used with classes.

  • Каждый класс может иметь только один метод завершения.A class can only have one finalizer.

  • Методы завершения не могут быть унаследованы или перегружены.Finalizers cannot be inherited or overloaded.

  • Методы завершения невозможно вызвать.Finalizers cannot be called. Они запускаются автоматически.They are invoked automatically.

  • Метод завершения не принимает модификаторов и не имеет параметров.A finalizer does not take modifiers or have parameters.

Например, ниже показано объявление метода завершения для класса Car.For example, the following is a declaration of a finalizer for the Car class.

class Car
{
    ~Car()  // finalizer
    {
        // cleanup statements...
    }
}

Метод завершения можно также реализовать как определение тела выражения, как показано в следующем примере.A finalizer can also be implemented as an expression body definition, as the following example shows.

using System;

public class Destroyer
{
   public override string ToString() => GetType().Name;
   
   ~Destroyer() => Console.WriteLine($"The {ToString()} destructor is executing.");
}

Метод завершения неявно вызывает метод Finalize для базового класса объекта.The finalizer implicitly calls Finalize on the base class of the object. В связи с этим вызов метода завершения неявно преобразуется в следующий код:Therefore, a call to a finalizer is implicitly translated to the following code:

protected override void Finalize()  
{  
    try  
    {  
        // Cleanup statements...  
    }  
    finally  
    {  
        base.Finalize();  
    }  
}  

Это означает, что метод Finalize вызывается рекурсивно для всех экземпляров цепочки наследования начиная с самого дальнего и заканчивая самым первым.This means that the Finalize method is called recursively for all instances in the inheritance chain, from the most-derived to the least-derived.

Примечание

Пустые методы завершения использовать нельзя.Empty finalizers should not be used. Если класс содержит метод завершения, то в очереди метода Finalize создается запись.When a class contains a finalizer, an entry is created in the Finalize queue. При вызове метода завершения вызывается сборщик мусора, выполняющий обработку очереди.When the finalizer is called, the garbage collector is invoked to process the queue. Если метод завершения пустой, это приводит только к ненужному снижению производительности.An empty finalizer just causes a needless loss of performance.

Программист не может управлять моментом вызова метода завершения, потому что этот момент определяется сборщиком мусора.The programmer has no control over when the finalizer is called because this is determined by the garbage collector. Сборщик мусора проверяет наличие объектов, которые больше не используются приложением.The garbage collector checks for objects that are no longer being used by the application. Если он считает, что какой-либо объект требует уничтожения, то вызывает метод завершения (при наличии) и освобождает память, используемую для хранения этого объекта.If it considers an object eligible for finalization, it calls the finalizer (if any) and reclaims the memory used to store the object.

В приложениях .NET Framework (но не в приложениях .NET Core) методы завершения также вызываются при выходе из программы.In .NET Framework applications (but not in .NET Core applications), finalizers are also called when the program exits.

Сборку мусора можно выполнить принудительно, вызвав метод Collect, но в большинстве случаев этого следует избегать из-за возможных проблем с производительностью.It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.

Использование методов завершения для освобождения ресурсовUsing finalizers to release resources

В целом язык C# не требует управления памятью в той степени, в какой это требуется в случае разработки кода на языке, не рассчитанном на среду выполнения со сборкой мусора.In general, C# does not require as much memory management as is needed when you develop with a language that does not target a runtime with garbage collection. Это связано с тем, что сборщик мусора платформы .NET Framework неявным образом управляет выделением и высвобождением памяти для объектов.This is because the .NET Framework garbage collector implicitly manages the allocation and release of memory for your objects. Однако при инкапсуляции приложением неуправляемых ресурсов, например окон, файлов и сетевых подключений, для высвобождения этих ресурсов следует использовать методы завершения.However, when your application encapsulates unmanaged resources such as windows, files, and network connections, you should use finalizers to free those resources. Если объект допускает завершение, то сборщик мусора выполняет метод Finalize этого объекта.When the object is eligible for finalization, the garbage collector runs the Finalize method of the object.

Освобождение ресурсов явным образомExplicit release of resources

В случае, когда приложением используется ценный внешний ресурс, также рекомендуется обеспечить способ высвобождения этого ресурса явным образом, прежде чем сборщик мусора освободит объект.If your application is using an expensive external resource, we also recommend that you provide a way to explicitly release the resource before the garbage collector frees the object. Для этого реализуется метод Dispose интерфейса IDisposable, который выполняет необходимую для объекта очистку.You do this by implementing a Dispose method from the IDisposable interface that performs the necessary cleanup for the object. Это может значительно повысить производительность приложения.This can considerably improve the performance of the application. Даже в случае использования такого явного управления ресурсами метод завершения становится резервным средством очистки ресурсов, если вызов метода Dispose выполнить не удастся.Even with this explicit control over resources, the finalizer becomes a safeguard to clean up resources if the call to the Dispose method failed.

Дополнительные сведения об очистке ресурсов см. в следующих разделах:For more details about cleaning up resources, see the following topics:

ПримерExample

В приведенном ниже примере создаются три класса, образующих цепочку наследования.The following example creates three classes that make a chain of inheritance. Класс First является базовым, класс Second является производным от класса First, а класс Third является производным от класса Second.The class First is the base class, Second is derived from First, and Third is derived from Second. Все три класса имеют методы завершения.All three have finalizers. В методе Main создается экземпляр самого дальнего в цепочке наследования класса.In Main, an instance of the most-derived class is created. При выполнении программы обратите внимание на то, что методы завершения для всех трех классов вызываются автоматически в порядке от самого дальнего до первого в цепочке наследования.When the program runs, notice that the finalizers for the three classes are called automatically, and in order, from the most-derived to the least-derived.

class First
{
    ~First()
    {
        System.Diagnostics.Trace.WriteLine("First's destructor is called.");
    }
}

class Second : First
{
    ~Second()
    {
        System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
    }
}

class Third : Second
{
    ~Third()
    {
        System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
    }
}

class TestDestructors
{
    static void Main()
    {
        Third t = new Third();
    }

}
/* Output (to VS Output Window):
    Third's destructor is called.
    Second's destructor is called.
    First's destructor is called.
*/

Спецификация языка C#C# language specification

Дополнительные сведения см. в разделе Деструкторы спецификация языка C# 6.0.For more information, see the Destructors section of the C# language specification.

См. такжеSee also