What is the Dispose and main purpose of dispose
“The main purpose of Dispose is to free unmanaged resources, like file handles, sockets, or database connections, that the garbage collector doesn’t manage. The GC will eventually release the object’s memory, but not the underlying unmanaged resource. By implementing IDisposable, I can release those resources deterministically, for example via a using block, which also cascades to any disposable objects my class holds.”
What the Garbage Collector (GC) Does
The GC only knows how to release managed memory (the memory allocated on the .NET heap).
Example: You create new Customer() → when the object is no longer referenced, GC will eventually reclaim the memory. ✅
But the GC does not know what a file handle, socket, or database connection really means. Those things are outside of .NET’s control — they are OS-level unmanaged resources.
When you use classes like:
FileStream
SqlConnection
Socket
They internally hold handles (like a pointer to a file, database connection, or OS resource). These handles are unmanaged, meaning .NET doesn’t know how to free them automatically.
So what does .NET do?
👉 These classes implement IDisposable, and inside Dispose(), they include explicit instructions to release those unmanaged resources (e.g., CloseHandle, closesocket, sqlite3_close, etc.).
If You Don’t Call Dispose
The object eventually gets garbage collected.
If the class also implements a finalizer (~FileStream()), then when GC runs, it will eventually call that finalizer, which calls the same cleanup logic as Dispose().
But this happens later, and meanwhile you may run out of file handles, sockets, or database connections.
A FileStream object contains an unmanaged file handle.
what happens if there is no dispose no finalizer?
If your class holds an unmanaged resource (like a file handle, database connection, or socket) and you don’t implement either Dispose() or a finalizer (~ClassName()), then:
The GC will eventually collect your managed object (the C# class instance).
But the underlying unmanaged resource will not be released, because the GC does not know how to release it.
Result: Resource leak (e.g., file handle stays open, memory from unmanaged heap is never freed, database connection stays locked).
class MyFile
{
private IntPtr fileHandle; // unmanaged resource
public MyFile(string path)
{
// Open file, store raw OS handle
fileHandle = OpenFile(path);
}
// No Dispose
// No Finalizer } ➡️ GC will eventually collect MyFile object, but the fileHandle stays allocated at the OS level. ➡️ The OS thinks the file is still open → process may run out of file handles → "Too many open files" error.If there is no dispose but only finalizer.
If you implement only a finalizer:
~MyFile()
{
CloseHandle(fileHandle);
}
The OS resource will eventually be released, but only when the GC runs and finalization happens.
This could take a long time (until memory pressure triggers a GC).
Also, finalizers run on a separate thread, so you have less control over when the resource is freed.
when to implement IDisposable?
2- Classes that use managed but scarce/expensive resources
Even if a class doesn’t hold unmanaged resources, it might still need Dispose() to release expensive managed objects deterministically.
Examples:
3- Custom application-level classes
Sometimes, you create your own class that manages other IDisposable objects.
Even if your class doesn’t touch unmanaged resources, you should implement IDisposable if it owns other IDisposable objects.
When would you add a finalizer in your class?
Only if your class directly holds unmanaged resources (like a raw OS handle, database connection handle, or unmanaged memory pointer).
What does GC.SuppressFinalize(this) do in Dispose()?
: Prevents the finalizer from running since resources are already cleaned, avoiding redundant cleanup and performance overhead.
Implement dispose
class MyClass : IDisposable
{
private FileStream file;
private bool disposed = false;
public MyClass()
{
file = new FileStream("example.txt", FileMode.Open);
}
~MyClass()
{
Dispose(false); // finalizer: don't touch managed resources
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed) return;
if (disposing)
{
// ✅ SAFE: Managed objects are still alive
file?.Close();
}
// ✅ Clean unmanaged resources here if any
disposed = true;
} }