Eventos
Compilación de Intelligent Apps
17 mar, 21 - 21 mar, 10
Únase a la serie de reuniones para crear soluciones de inteligencia artificial escalables basadas en casos de uso reales con compañeros desarrolladores y expertos.
Regístrese ahoraEste explorador ya no se admite.
Actualice a Microsoft Edge para aprovechar las características y actualizaciones de seguridad más recientes, y disponer de soporte técnico.
Los finalizadores (anteriormente conocidos como destructores) se usan para realizar cualquier limpieza final necesaria cuando el recolector de elementos no utilizados recopila una instancia de clase. En la mayoría de los casos, puede evitar escribir un finalizador mediante System.Runtime.InteropServices.SafeHandle o clases derivadas para encapsular cualquier identificador no administrado.
Por ejemplo, el siguiente código muestra una declaración de un finalizador para la clase Car
.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
Un finalizador también puede implementarse como una definición de cuerpo de expresión, como se muestra en el ejemplo siguiente.
public class Destroyer
{
public override string ToString() => GetType().Name;
~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}
El finalizador llama implícitamente a Finalize en la clase base del objeto. Por lo tanto, una llamada a un finalizador se convierte implícitamente al siguiente código:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
Este diseño significa que se realizan llamadas al método Finalize
de manera recursiva para todas las instancias de la cadena de herencia, desde la más a la menos derivada.
Nota
Los finalizadores vacíos no deben usarse. Cuando una clase contiene un finalizador, se crea una entrada en la cola Finalize
. El recolector de elementos no utilizados procesa esta cola. Cuando esto sucede, llama a cada finalizador. Los finalizadores innecesarios, como los vacíos, los que solo llaman al finalizador de clase base o los que solo llaman a métodos emitidos condicionalmente provocan una pérdida innecesaria de rendimiento.
El programador no puede controlar cuándo se llama al finalizador; es el recolector de elementos no utilizados el que decide cuándo hacerlo. El recolector de elementos no utilizados comprueba si hay objetos que ya no están siendo usados por ninguna aplicación. Si considera un objeto elegible para su finalización, llama al finalizador (si existe) y reclama la memoria usada para almacenar el objeto. Es posible forzar la recolección de elementos no utilizados si se llama a Collect, pero debe evitarse esta llamada porque puede dar lugar a problemas de rendimiento.
Nota
El hecho de que los finalizadores se ejecuten o no como parte de la finalización de aplicaciones es específico de cada implementación de .NET. Cuando finaliza una aplicación, .NET Framework hace todo lo posible para llamar a todos los finalizadores en los objetos cuyos elementos no se han detectado durante la recolección de elementos no utilizados, a menos que se haya suprimido esa limpieza (por ejemplo, mediante una llamada al método de biblioteca GC.SuppressFinalize
). En .NET 5 (incluido .NET Core) y versiones posteriores no se llama a los finalizadores como parte de la finalización de la aplicación. Para obtener más información, vea la incidencia de GitHub dotnet/csharpstandard n.º 291.
Si necesita realizar la limpieza de forma confiable cuando existe una aplicación, registre un controlador para el evento System.AppDomain.ProcessExit. Ese controlador garantizaría la llamada a IDisposable.Dispose(), o a IAsyncDisposable.DisposeAsync(), para todos los objetos que requieren limpieza antes de que la aplicación se cierre. Dado que no se puede llamar directamente a Finalizar y no se puede garantizar que el recolector de elementos no utilizados llame a todos los finalizadores antes de salir, debe usar Dispose
o DisposeAsync
para asegurarse de que se liberan los recursos.
En general, C# no requiere tanta administración de memoria por parte del desarrollador como los lenguajes que no están diseñados para un runtime con recolección de elementos no utilizados. Esto es debido a que el recolector de elementos no utilizados de .NET administra implícitamente la asignación y liberación de memoria para los objetos. En cambio, cuando la aplicación encapsule recursos no administrados, como ventanas, archivos y conexiones de red, debería usar finalizadores para liberar dichos recursos. Cuando el objeto cumple los requisitos para su finalización, el recolector de elementos no utilizados ejecuta el método Finalize
del objeto.
Si la aplicación usa un recurso externo costoso, también es recomendable liberar explícitamente el recurso antes de que el recolector de elementos no utilizados libere el objeto. Para liberar el recurso, implemente un método Dispose
desde la interfaz IDisposable que realiza la limpieza necesaria del objeto. Esto puede mejorar considerablemente el rendimiento de la aplicación. Aun con este control explícito sobre los recursos, el finalizador se convierte en una salvaguarda para limpiar recursos si se produce un error en la llamada al método Dispose
.
Para obtener más información sobre la limpieza de recursos, vea los siguientes artículos:
using
En el siguiente ejemplo se crean tres clases que forman una cadena de herencia. La clase First
es la clase base, Second
se deriva de First
y Third
se deriva de Second
. Los tres tienen finalizadores. En Main
, se crea una instancia de la clase más derivada. La salida de este código depende de la implementación de .NET a la que se dirige la aplicación:
class First
{
~First()
{
System.Diagnostics.Trace.WriteLine("First's finalizer is called.");
}
}
class Second : First
{
~Second()
{
System.Diagnostics.Trace.WriteLine("Second's finalizer is called.");
}
}
class Third : Second
{
~Third()
{
System.Diagnostics.Trace.WriteLine("Third's finalizer is called.");
}
}
/*
Test with code like the following:
Third t = new Third();
t = null;
When objects are finalized, the output would be:
Third's finalizer is called.
Second's finalizer is called.
First's finalizer is called.
*/
Para más información, consulte la sección Finalizadores de la especificación del lenguaje C#.
Comentarios de .NET
.NET es un proyecto de código abierto. Seleccione un vínculo para proporcionar comentarios:
Eventos
Compilación de Intelligent Apps
17 mar, 21 - 21 mar, 10
Únase a la serie de reuniones para crear soluciones de inteligencia artificial escalables basadas en casos de uso reales con compañeros desarrolladores y expertos.
Regístrese ahoraCursos
Módulo
Administrar implementaciones de clases - Training
Obtenga información sobre cómo implementar clases mediante técnicas avanzadas como clases estáticas, clases parciales e inicializadores de objetos que pueden mejorar la legibilidad, el mantenimiento y la organización del código.
Documentación
Constructores de estructura sin parámetros - C# feature specifications
Esta función especifica constructores de estructuras sin parámetros, que ahora pueden declararse para estructuras. Las reglas para cuando se les llama describen el comportamiento en matrices y otras declaraciones de variables.
Implementación de un método Dispose - .NET
En este artículo, aprenderá a implementar el método Dispose, que libera recursos no administrados usados por el código en .NET.
Instrucción using: asegúrese del uso correcto de objetos descartables - C# reference
Use la instrucción o declaración de C# para garantizar el uso correcto de los objetos descartables