Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to implement IDisposable Design Pattern in C#?
The IDisposable design pattern (also called the Dispose Pattern) in C# is used to properly clean up unmanaged resources like file handles, database connections, and network streams. This pattern ensures that resources are released deterministically, rather than waiting for the garbage collector.
Classes that directly or indirectly use unmanaged resources should implement the IDisposable interface. This includes classes that use FileStream, HttpClient, database connections, or any other objects that hold system resources.
Syntax
Following is the basic syntax for implementing IDisposable −
public class ClassName : IDisposable {
private bool disposed = false;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
// Dispose managed resources
}
// Clean up unmanaged resources
disposed = true;
}
}
~ClassName() {
Dispose(false);
}
}
Key Components of the Pattern
Using IDisposable with File Operations
Example
using System;
using System.IO;
public class FileManager : IDisposable {
private FileStream fileStream;
private bool disposed = false;
public FileManager(string fileName) {
fileStream = new FileStream(fileName, FileMode.Create);
}
public void WriteData(string data) {
if (disposed) {
throw new ObjectDisposedException("FileManager");
}
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
fileStream.Write(bytes, 0, bytes.Length);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
// Dispose managed resources
fileStream?.Dispose();
}
// Clean up unmanaged resources here if any
disposed = true;
}
}
~FileManager() {
Dispose(false);
}
}
class Program {
static void Main(string[] args) {
using (var fileManager = new FileManager("test.txt")) {
fileManager.WriteData("Hello, World!");
fileManager.WriteData("IDisposable Pattern Example");
} // Dispose() called automatically
Console.WriteLine("File operations completed and resources disposed.");
}
}
The output of the above code is −
File operations completed and resources disposed.
Using 'using' Statement for Automatic Disposal
Example
using System;
public class DatabaseConnection : IDisposable {
private string connectionString;
private bool disposed = false;
public DatabaseConnection(string connString) {
connectionString = connString;
Console.WriteLine("Database connection opened");
}
public void ExecuteQuery(string query) {
if (disposed) {
throw new ObjectDisposedException("DatabaseConnection");
}
Console.WriteLine($"Executing query: {query}");
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
Console.WriteLine("Database connection closed");
}
disposed = true;
}
}
~DatabaseConnection() {
Dispose(false);
}
}
class Program {
static void Main(string[] args) {
// Using statement ensures automatic disposal
using var connection = new DatabaseConnection("server=localhost;database=test");
connection.ExecuteQuery("SELECT * FROM users");
connection.ExecuteQuery("UPDATE users SET active=1");
Console.WriteLine("Operations completed");
} // Dispose() called automatically here
}
The output of the above code is −
Database connection opened Executing query: SELECT * FROM users Executing query: UPDATE users SET active=1 Operations completed Database connection closed
IDisposable with Inheritance
Example
using System;
public class BaseResource : IDisposable {
private bool disposed = false;
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
Console.WriteLine("BaseResource: Disposing managed resources");
}
Console.WriteLine("BaseResource: Disposing unmanaged resources");
disposed = true;
}
}
~BaseResource() {
Dispose(false);
}
}
public class DerivedResource : BaseResource {
private bool disposed = false;
protected override void Dispose(bool disposing) {
if (!disposed) {
if (disposing) {
Console.WriteLine("DerivedResource: Disposing managed resources");
}
Console.WriteLine("DerivedResource: Disposing unmanaged resources");
disposed = true;
}
// Call base class Dispose method
base.Dispose(disposing);
}
}
class Program {
static void Main(string[] args) {
using var resource = new DerivedResource();
Console.WriteLine("Resource created and used");
} // Dispose chain called automatically
}
The output of the above code is −
Resource created and used DerivedResource: Disposing managed resources DerivedResource: Disposing unmanaged resources BaseResource: Disposing managed resources BaseResource: Disposing unmanaged resources
Best Practices
-
Always call
GC.SuppressFinalize(this)in the publicDispose()method to prevent the finalizer from running. -
Make the protected
Dispose(bool disposing)method virtual so derived classes can override it. -
Check the
disposedflag to prevent multiple dispose calls. -
Use the
usingstatement orusingdeclaration for automatic disposal. -
Throw
ObjectDisposedExceptionwhen methods are called after disposal.
Conclusion
The IDisposable design pattern in C# provides a standardized way to release unmanaged resources deterministically. It consists of a public Dispose() method, a protected virtual Dispose(bool disposing) method, and optionally a finalizer for backup cleanup. Use the using statement to ensure automatic disposal and prevent resource leaks.
