Destruktor och Finalizer
En destruktor (eller finalizer) är kod som körs när ett objekt förstörs. I C# hanteras minnet automatiskt av Garbage Collector — destruktorn är sällan nödvändig.
När du läst detta ska du kunna
- Förklara vad en destruktor är och när den körs
- Skriva en destruktor i C#
- Förstå varför destruktorer är sällsynta i C#
- Använda
IDisposableochusingsom ett bättre alternativ
Destruktor — syntax
En destruktor har klassens namn med ett ~ framför. Den tar inga parametrar och har inget returvärde.
public class Resource{ public Resource() { Console.WriteLine("Resurs skapades"); }
// Destruktor — körs av GC när objektet städas bort ~Resource() { Console.WriteLine("Resurs förstördes"); }}
{ var r = new Resource(); // Resurs skapades // r går ur scope här}// "Resurs förstördes" skrivs ut... men när? GC bestämmer.Output (ungefärlig)
Resurs skapadesResurs förstördesVarför är destruktorer sällsynta i C#?
Destruktorn omvandlas av kompilatorn till en finalizer och körs av Garbage Collector (GC). Problemet:
- Du vet inte när GC kör den — det kan dröja länge
- Finalizerkön är trög och fördröjer GC:n
- Objekt med finalizer lever ett extra GC-varv längre
- Det är svårt att skriva korrekt kod i en finalizer
För hanterade resurser (vanliga C#-objekt) behöver du aldrig en destruktor — GC tar hand om allt.
IDisposable — rätt väg för ohanterade resurser
Om din klass håller en ohanterad resurs (filhandle, databaskoppling, nätverksanslutning) använder du IDisposable istället.
public class FilePrinter : IDisposable{ private StreamWriter _writer; private bool _disposed = false;
public FilePrinter(string path) { _writer = new StreamWriter(path); }
public void Write(string text) => _writer.WriteLine(text);
public void Dispose() { if (!_disposed) { _writer?.Dispose(); _disposed = true; } }}
// using-blocket anropar Dispose() automatiskt när blocket är klartusing (var file = new FilePrinter("log.txt")){ file.Write("Hej från fil!");}// Dispose() har körts — filen är stängdKortare using-syntax (C# 8) ✨
// ✨ C# 8 — ingen explicit block behövsusing var file = new FilePrinter("log.txt");file.Write("Hej från fil!");// Dispose() körs automatiskt när variabeln lämnar scopeKombination: IDisposable + finalizer
Standardmönstret (Dispose pattern) kombinerar båda för att hantera både kontrollerad (Dispose) och okontrollerad (GC) frigöring.
public class HandledResource : IDisposable{ private bool _disposed = false;
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // Frigör hanterade resurser } // Frigör ohanterade resurser (om du har dem) _disposed = true; } }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // Säger åt GC att skippa finalizern }
~HandledResource() => Dispose(false); // Säkerhetsnät om Dispose glömdes}TL;DR
- Destruktor (
~Class()) körs av GC — du vet inte när - Sällsynt i C# eftersom GC hanterar minnet automatiskt
- För ohanterade resurser: implementera
IDisposableoch användusing using var(C# 8) är kortast och anroparDispose()automatiskt
Se även: Garbage Collector