Finalizační metody (Průvodce programováním v C#)

Finalizační metody (označované jako destruktory) se používají k provedení jakéhokoli nezbytného konečného vyčištění, když je instance třídy shromažďována systémem uvolňování paměti. Ve většině případů se můžete vyhnout psaní finalizační metody pomocí tříd nebo odvozených tříd k zabalení jakéhokoli System.Runtime.InteropServices.SafeHandle 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 jednu finalizační metodu.
  • Finalizační metody nelze dědit ani přetížit.
  • Finalizační metody nelze volat. Jsou vyvolány automaticky.
  • Finalizační metoda nepřichytá modifikátory ani nemá parametry.

Například následující je deklarace finalizační metody pro Car třídu.

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

Finalizační metodu je také možné 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()} destructor is executing.");
}

Finalizační metoda Finalize implicitně volá základní třídu objektu . Proto se volání finalizační metody implicitně přeloží do následujícího kódu:

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

Tento návrh znamená, že metoda je volána rekurzivně pro všechny instance v řetězci dědičnosti, od nejdéle odvozených po nejméně Finalize odvozené.

Poznámka

Neměly by se používat prázdné finalizační metody. Pokud třída obsahuje finalizační metodu, vytvoří se ve frontě Finalize položka. Při volání finalizační metody se vyvolá systém uvolňování paměti, který zpracuje frontu. Prázdná finalizační metoda jen způsobí zbytečně ztrátu výkonu.

Programátor nemá žádnou kontrolu nad voláním finalizační metody. Systém uvolňování paměti se rozhodne, kdy ho volat. Systém uvolňování paměti vyhledá objekty, které už aplikace nebude používat. Pokud považuje objekt způsobilý k finalizaci, volá finalizační metodu (pokud je k dispozici) a znovu získá paměť použitou k uložení objektu. Uvolnění paměti je možné vynutit voláním , ale ve většině času byste se měli tomuto volání vyhnout, protože může dojít k Collect problémům s výkonem.

Poznámka

To, zda jsou finalizační metody spuštěny jako součást ukončení aplikace, je specifické pro každou implementaci rozhraní .NET. Když se aplikace ukončí, .NET Framework vynaložit veškeré přiměřené úsilí na volání finalizačních metod pro objekty, které ještě nebyly uvolněny z paměti, pokud takové vyčištění nebylo potlačeno (například voláním metody GC.SuppressFinalize knihovny ). .NET 5 (včetně .NET Core) a novější verze nevolají finalizační metody jako součást ukončení aplikace. Další informace najdete v tématu GitHub dotnet/csharpstandard #291.

Pokud potřebujete provést spolehlivé vyčištění po ukončení aplikace, zaregistrujte obslužnou rutinu System.AppDomain.ProcessExit události. Tato obslužná rutina by zajistila volání nebo pro všechny objekty, IDisposable.Dispose() které vyžadují vyčištění před IAsyncDisposable.DisposeAsync() ukončením aplikace. Vzhledem k tomu, že nemůžete volat Finalize přímo a nemůžete zaručit, že systém uvolňování paměti zavolá všechny finalizační metody před ukončením, musíte použít nebo , abyste zajistili uvolnění Dispose DisposeAsync prostředků.

Použití finalizačních metod k vydání prostředků

Jazyk C# obecně nevyžaduje na straně vývojáře tolik paměti jako jazyky, které nejsou cílem modulu runtime s uvolňováním paměti. Je to proto, ž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 okna, soubory a síťová připojení, měli byste tyto prostředky volná pomocí finalizačních metod. Pokud je objekt způsobilý k dokončení, spustí systém uvolňování paměti Finalize metodu objektu .

Explicitní vypouštění prostředků

Pokud vaše aplikace používá nákladný externí prostředek, doporučujeme také poskytnout způsob, jak prostředek explicitně uvolnit, než systém uvolňování paměti uvolní objekt . Chcete-li uvolnit prostředek, implementujte metodu z rozhraní, které provádí Dispose IDisposable nezbytné vyčištění objektu. To může výrazně zlepšit výkon aplikace. I s touto explicitní kontrolou nad prostředky se finalizační metoda stane bezpečnostním opatřením pro vyčištění prostředků v případě, že volání Dispose metody selže.

Další informace o vyčištění prostředků najdete v následujících článcích:

Příklad

Následující příklad vytvoří tři třídy, které tvoří řetěz dědičnosti. Třída je First základní třída, Second je odvozena z třídy a je First Third odvozena z třídy Second . Všechny tři mají finalizační metody. V Main je vytvořena instance nejdél odvozené třídy. Výstup z tohoto kódu závisí na tom, na kterou implementaci .NET 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 odvozených po nejméně odvozené.
  • .NET 5 (včetně .NET Core) nebo novější verze: Neexistuje žádný výstup, protože tato implementace .NET nevolá finalizační metody při ukončení aplikace.
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 najdete v části Destruktory specifikace jazyka C#.

Viz také