Finalizers (C# programozási útmutató)
A véglegesítők (korábbi nevén destruktorok) a szükséges végleges tisztítás végrehajtására szolgálnak, amikor a szemétgyűjtő összegyűjt egy osztálypéldányt. A legtöbb esetben elkerülheti a véglegesítő írását, ha a nem felügyelt leírók burkolására használja az System.Runtime.InteropServices.SafeHandle vagy származtatott osztályokat.
Megjegyzések
- A véglegesítők nem definiálhatók a szerkezetekben. Csak osztályokkal használják őket.
- Egy osztálynak csak egy döntőse lehet.
- A véglegesítők nem örökölhetők vagy túlterhelhetők.
- A döntőzők nem hívhatók meg. A rendszer automatikusan meghívja őket.
- A véglegesítők nem fogadnak módosítókat, és nem rendelkeznek paraméterekkel.
Az alábbiakban például az osztály döntősének deklarációja látható Car
.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
A véglegesítő kifejezés törzsdefinícióként is implementálható, ahogy az alábbi példa is mutatja.
public class Destroyer
{
public override string ToString() => GetType().Name;
~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}
A véglegesítő implicit módon meghívja Finalize az objektum alaposztályát. Ezért a véglegesítő hívás implicit módon a következő kódra lesz lefordítva:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
Ez a kialakítás azt jelenti, hogy a Finalize
metódust rekurzívan nevezik az öröklési lánc összes példányára, a legtöbb származtatotttól a legkevésbé származtatottig.
Feljegyzés
Üres véglegesítőket nem szabad használni. Ha egy osztály véglegesítőt tartalmaz, a rendszer létrehoz egy bejegyzést az Finalize
üzenetsorban. Ezt az üzenetsort a szemétgyűjtő dolgozza fel. Amikor a GC feldolgozza az üzenetsort, meghívja az egyes véglegesítőket. A szükségtelen véglegesítők, beleértve az üres döntősöket, a csak az alaposztály-döntőzőt meghívó döntősöket, vagy a csak feltételesen kibocsátott metódusokat hívó döntősök szükségtelen teljesítménycsökkenést okoznak.
A programozó nem szabályozhatja a döntőző meghívását; a szemétgyűjtő dönti el, hogy mikor hívja meg. A szemétgyűjtő ellenőrzi azokat az objektumokat, amelyeket az alkalmazás már nem használ. Ha úgy véli, hogy egy objektum jogosult a véglegesítésre, meghívja a véglegesítőt (ha van ilyen), és visszanyeri az objektum tárolásához használt memóriát. A hívással Collectkényszeríthető a szemétgyűjtés, de a legtöbb esetben ezt a hívást el kell kerülni, mert teljesítményproblémákat okozhat.
Feljegyzés
A .NET minden implementációjára jellemző, hogy a véglegesítők az alkalmazásleállítás részeként futnak-e. Amikor egy alkalmazás leáll, .NET-keretrendszer minden ésszerű erőfeszítést megtesz annak érdekében, hogy véglegesítőket hívjon meg olyan objektumokhoz, amelyeket még nem gyűjtöttek össze, kivéve, ha az ilyen törlést letiltották (például a kódtár metódusának GC.SuppressFinalize
hívásával). A .NET 5 (beleértve a .NET Core-t) és a későbbi verziók nem hívják meg a véglegesítőket az alkalmazás leállítása részeként. További információ: GitHub-probléma dotnet/csharpstandard #291.
Ha megbízhatóan kell elvégeznie a tisztítást, amikor egy alkalmazás kilép, regisztráljon egy kezelőt az System.AppDomain.ProcessExit eseményhez. Ez a kezelő biztosítja IDisposable.Dispose() (vagy) az összes olyan objektum meghívását, IAsyncDisposable.DisposeAsync()amely törlést igényel az alkalmazás kilépése előtt. Mivel nem hívhatja meg közvetlenül a Finalize-t, és nem garantálhatja, hogy a szemétgyűjtő minden véglegesítőt meghív a kilépés előtt, az erőforrások felszabadításához vagy DisposeAsync
használatához kell használniaDispose
.
Véglegesítők használata erőforrások kiadásához
A C# általában nem igényel annyi memóriakezelést a fejlesztő részéről, mint a szemétgyűjtéssel nem rendelkező futtatókörnyezetet megcélozó nyelvek. Ennek az az oka, hogy a .NET szemétgyűjtő implicit módon kezeli az objektumok memóriafoglalását és felszabadítását. Ha azonban az alkalmazás nem felügyelt erőforrásokat, például windowsokat, fájlokat és hálózati kapcsolatokat foglal magában, a véglegesítőkkel szabadíthatja fel ezeket az erőforrásokat. Ha az objektum jogosult a véglegesítésre, a szemétgyűjtő futtatja az Finalize
objektum metódusát.
Erőforrások explicit kiadása
Ha az alkalmazás költséges külső erőforrást használ, azt is javasoljuk, hogy adjon módot az erőforrás explicit kiadására, mielőtt a szemétgyűjtő felszabadítja az objektumot. Az erőforrás felszabadításához implementáljon egy metódust Dispose
a IDisposable felületről, amely elvégzi az objektumhoz szükséges tisztítást. Ez jelentősen javíthatja az alkalmazás teljesítményét. Az erőforrások explicit vezérlése mellett is a véglegesítő védelmet nyújt az erőforrások megtisztításához, ha a Dispose
metódus meghívása sikertelen.
Az erőforrások megtisztításáról az alábbi cikkekben talál további információt:
- Nem felügyelt erőforrások tisztítása
- Megsemmisítési módszer implementálása
- DisposeAsync metódus implementálása
- utasítás használata
Példa
Az alábbi példa három osztályt hoz létre, amelyek öröklési láncot alkotnak. Az osztály First
az alaposztály, Second
a származtatása First
és Third
a származtatása Second
. Mindhárman döntősök. Ebben Main
a fájlban létrejön a legtöbb származtatott osztály egy példánya. A kód kimenete attól függ, hogy az alkalmazás melyik .NET-implementációt célozza meg:
- .NET-keretrendszer: A kimenet azt mutatja, hogy a három osztály véglegesítőit a rendszer automatikusan meghívja az alkalmazás leállásakor, a legtöbb származtatotttól a legkevésbé származtatottig.
- .NET 5 (beleértve a .NET Core-t) vagy egy újabb verzió: Nincs kimenet, mert a .NET ezen implementációja nem hív meg véglegesítőket az alkalmazás leállásakor.
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.
*/
C# nyelvspecifikáció
További információkért lásd a C#-nyelv specifikációjának Finalizers szakaszát.
Lásd még
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: