Finalizační metody (Průvodce programováním v C#)
Finalizační metody (historicky označované jako destruktory) se používají k provedení všech nezbytných finálních vyčištění, pokud je instance třídy shromažďována systémem uvolňování paměti. Ve většině případů se můžete vyhnout zápisu finalizační metody pomocí System.Runtime.InteropServices.SafeHandle odvozené třídy nebo pro zabalení jakéhokoli nespravovaného popisovače.
Poznámky
- Finalizační metody nelze definovat ve strukturách. Používají se pouze s třídami.
- Třída může mít pouze jeden finalizační metodu.
- Finalizační metody nemůžou být zděděné nebo přetížené.
- Finalizační metody nelze volat. Jsou vyvolány automaticky.
- Finalizační metoda nepřijímá modifikátory nebo má parametry.
Například následující je deklarace finalizační metody pro Car třídu.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
Finalizační metodu lze také implementovat jako definici těla výrazu, jak ukazuje následující příklad.
using System;
public class Destroyer
{
public override string ToString() => GetType().Name;
~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}
Finalizační metoda implicitně volá Finalize základní třídu objektu. Proto volání finalizační metody je implicitně přeloženo na následující kód:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
Tento návrh znamená, že Finalize Metoda je volána rekurzivně pro všechny instance v řetězu dědičnosti, od nejvíce odvozené k nejméně odvozenému.
Poznámka
Nemusíte používat prázdné finalizační metody. Pokud třída obsahuje finalizační metodu, je ve Finalize frontě vytvořena položka. Tato fronta zpracovává systém uvolňování paměti. Když GC zpracuje frontu, zavolá každý finalizační metodu. Nepotřebné finalizační metody, včetně prázdných finalizační metody, finalizační metody, které volají pouze finalizační metodu základní třídy nebo finalizační metody, které volají pouze podmíněné metody, způsobují nepotřebnou ztrátu výkonu.
Programátor nemá žádnou kontrolu nad tím, kdy se volá finalizační metoda; systém uvolňování paměti určuje, kdy se má zavolat. Systém uvolňování paměti kontroluje objekty, které již aplikace nepoužívá. Pokud se považuje za objekt s nárokem na finalizaci, zavolá finalizační metodu (pokud existuje) a uvolní paměť použitou k uložení objektu. Je možné vynutit uvolňování paměti voláním Collect , ale většinou v čase, toto volání by se mělo vyhnout, protože může způsobit problémy s výkonem.
Poznámka
Bez ohledu na to, jestli jsou finalizační metody spuštěné jako součást ukončení aplikace, jsou specifické pro každou implementaci rozhraní .NET. když se aplikace ukončí, .NET Framework provede každé přiměřené úsilí volat finalizační metody pro objekty, které ještě nebyly shromážděny z paměti, pokud takové vyčištění nebylo potlačeno (například voláním metody knihovny GC.SuppressFinalize , například). Rozhraní .NET 5 (včetně .NET Core) a novějších verzí nevolají finalizační metody jako součást ukončení aplikace. další informace naleznete v tématu GitHub issueing dotnet/csharpstandard #291.
Pokud potřebujete provést vyčištění spolehlivě při ukončení aplikace, zaregistrujte obslužnou rutinu pro System.AppDomain.ProcessExit událost. Tato obslužná rutina by zajistila, že IDisposable.Dispose() (nebo, IAsyncDisposable.DisposeAsync() ) byla volána pro všechny objekty, které vyžadují vyčištění před ukončením aplikace. Vzhledem k tomu, že nemůžete volat metodu Finalize přímo a nemůžete zajistit, aby systém uvolňování paměti před ukončením volal všechny finalizační metody, je nutné použít Dispose nebo DisposeAsync k zajištění uvolnění prostředků.
Použití finalizační metody k uvolnění prostředků
Obecně platí, že v jazyce C# není pro vývojáře v rámci jazyků, které necílí na modul runtime s uvolňováním paměti, potřeba tolik správy paměti. Důvodem je to, že systém uvolňování paměti .NET implicitně spravuje přidělování a uvolňování paměti pro vaše objekty. Pokud však vaše aplikace zapouzdřuje nespravované prostředky, jako jsou například Windows, soubory a síťová připojení, měli byste k uvolnění těchto prostředků použít finalizační metody. Pokud je objekt způsobilý pro finalizaci, systém uvolňování paměti spustí Finalize metodu objektu.
Explicitní vydání prostředků
Pokud vaše aplikace používá nákladný externí prostředek, doporučujeme vám, abyste poskytli způsob, jak prostředek explicitně uvolnit před tím, než systém uvolňování paměti uvolní objekt. Chcete-li uvolnit prostředek, implementujte Dispose metodu z IDisposable rozhraní, které provádí nezbytné vyčištění objektu. To může výrazně zlepšit výkon aplikace. I s tímto explicitním ovládáním prostředků se finalizační metoda stala ochranou pro vyčištění prostředků, pokud volání Dispose metody neproběhne úspěšně.
Další informace o čištění prostředků najdete v následujících článcích:
- Vymazání nespravovaných prostředků
- Implementace metody Dispose
- Implementace metody DisposeAsync
- using – příkaz
Příklad
Následující příklad vytvoří tři třídy, které tvoří řetěz dědičnosti. Třída First je základní třídou, Second je odvozena z First a Third je odvozena z Second . Všechny tři mají finalizační metody. V je Main vytvořena instance nejvíce odvozené třídy. Výstup z tohoto kódu závisí na implementaci .NET, na kterou cílí aplikace:
- .NET Framework: výstup ukazuje, že finalizační metody pro tři třídy jsou volány automaticky při ukončení aplikace, v pořadí od nejvíce odvozené k nejméně odvozenému.
- .NET 5 (včetně .NET Core) nebo novější verze: není k dispozici žádný výstup, protože tato implementace .NET nevolá finalizační metody, když se aplikace ukončí.
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.
*/
specifikace jazyka C#
Další informace naleznete v části destruktory specifikace jazyka C#.