Destructor vs IDisposable?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
In C#, destructors (finalizers) and IDisposable both handle resource cleanup, but they work differently. IDisposable.Dispose() is called explicitly by your code (often via using) and runs deterministically — you know exactly when cleanup happens. A destructor (~ClassName) is called by the garbage collector at an unpredictable time. For unmanaged resources (file handles, database connections, network sockets), always implement IDisposable. Use a destructor only as a safety net in case Dispose() was never called.
Destructor (Finalizer)
Key characteristics:
- Called by the garbage collector, not by your code
- Cannot predict when (or if) it will run
- Adds GC overhead — objects with finalizers take two GC cycles to collect
- Cannot access other managed objects (they may already be collected)
- One finalizer per class, no parameters, no access modifiers
IDisposable
Key characteristics:
- Called explicitly by the developer
- Runs at a known, predictable time
- Can clean up both managed and unmanaged resources
- Works with the
usingstatement /usingdeclaration - No GC overhead
The Dispose Pattern (Combining Both)
The standard pattern implements both as a safety net:
Dispose(true)— called fromDispose(), cleans up everythingDispose(false)— called from finalizer, only cleans up unmanaged resourcesGC.SuppressFinalize(this)— tells the GC not to run the finalizer since cleanup is done
Using Statement
The using statement guarantees Dispose() is called even if an exception occurs — it compiles to a try-finally block.
When to Use Each
| Scenario | Use |
| File handles, streams | IDisposable with using |
| Database connections | IDisposable with using |
| Network sockets | IDisposable with using |
| Unmanaged memory (IntPtr) | IDisposable + finalizer safety net |
| Event handler unsubscription | IDisposable |
| Pure managed objects | Neither (let GC handle it) |
| Third-party native library wrappers | Full Dispose pattern with finalizer |
IAsyncDisposable (C# 8+)
For async cleanup operations:
GC Performance Impact
Objects with finalizers always survive to Gen 1 or Gen 2, making them much more expensive to collect. Always call GC.SuppressFinalize in Dispose().
Common Pitfalls
- Only implementing a destructor: Destructors run at unpredictable times and add GC overhead. Always implement
IDisposablefor deterministic cleanup. Use the destructor only as a fallback. - Forgetting
GC.SuppressFinalize: Without this, the finalizer runs even afterDispose()has already cleaned up, wasting time and potentially causing errors from double cleanup. - Accessing managed objects in the finalizer: When the finalizer runs, other managed objects may already be garbage collected. Only clean up unmanaged resources in the finalizer (
Dispose(false)path). - Not calling
Dispose()/ not usingusing: Creating anIDisposableobject withoutusingor manualDispose()leaks the resource until the GC eventually runs the finalizer (if one exists). - Disposing objects you do not own: If a method receives an
IDisposableas a parameter, do not dispose it unless the method is documented as taking ownership. The caller may still need it.
Summary
IDisposable.Dispose()is deterministic — called explicitly, runs immediately- Destructors are non-deterministic — called by GC at an unpredictable time
- Use
IDisposablewithusingfor all resource cleanup - Add a destructor only as a safety net for unmanaged resources
- Always call
GC.SuppressFinalize(this)inDispose()to avoid double cleanup - The full Dispose pattern handles both managed (
disposing: true) and unmanaged resources
Related reading
- Detect if deserialized object is missing a field with the JsonConvert class in Json.NET Newtonsoft
- Detect Windows version in .NET
- Detected package downgrade warning dotnet core, vs 2017
- Detecting async client disconnect in ASP.NET MVC
- Detecting USB drive insertion and removal using windows service and c
- Determine if ASP.NET application is running locally
- Determine .NET Framework version for dll
- Determine via C whether a string is a valid file path

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.