C#
memory management
garbage collection
IDisposable
object lifecycle

Setting an object to null vs Dispose

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In .NET, setting an object reference to null and calling Dispose() solve different problems. Setting a variable to null only removes that particular reference. Dispose() is about releasing resources deterministically, especially resources the garbage collector does not manage well on its own, such as file handles, sockets, and database connections.

What Setting a Reference to null Actually Does

When you write:

csharp
MyType obj = new MyType();
obj = null;

you are not destroying the object. You are only removing one reference to it. If no reachable references remain, the object becomes eligible for garbage collection at some later time. The timing is not deterministic.

That means setting a variable to null does not immediately:

  • free managed memory
  • close a file
  • release a database connection
  • dispose of unmanaged resources

It only changes your program's reference graph.

What Dispose() Is For

Dispose() is used by types that implement IDisposable. It exists so code can release resources as soon as you are done with them.

Example with a file stream:

csharp
1using System;
2using System.IO;
3
4FileStream stream = File.OpenRead("data.txt");
5stream.Dispose();

Calling Dispose() closes the underlying OS resource immediately. The object may still exist in memory until the garbage collector eventually reclaims it, but the important external resource is already released.

That is the key distinction:

  • garbage collection manages memory
  • 'Dispose() manages resource lifetime'

Why Garbage Collection Is Not Enough

The .NET garbage collector is good at cleaning up managed memory, but it does not promise when final cleanup happens. That is fine for ordinary objects. It is not fine for scarce resources.

Imagine opening many files without disposing them:

csharp
1using System.IO;
2
3for (int i = 0; i < 1000; i++)
4{
5    var reader = File.OpenText("data.txt");
6    // no Dispose
7}

Even if those readers become unreachable, the file handles may stay open long enough to cause failures or resource exhaustion.

That is why IDisposable exists. It gives you a deterministic cleanup point.

The Correct Pattern: using

The usual C# pattern is not "call Dispose() manually everywhere." It is using, which guarantees disposal even if an exception occurs.

csharp
1using System.IO;
2
3using (var reader = File.OpenText("data.txt"))
4{
5    string content = reader.ReadToEnd();
6    System.Console.WriteLine(content);
7}

Modern C# also supports the using declaration:

csharp
1using System.IO;
2
3using var reader = File.OpenText("data.txt");
4string content = reader.ReadToEnd();
5System.Console.WriteLine(content);

These forms are safer and clearer than relying on null assignments.

Should You Set a Disposed Object to null

Usually, no.

This code:

csharp
FileStream stream = File.OpenRead("data.txt");
stream.Dispose();
stream = null;

rarely adds meaningful value. After disposal, the key resource is already released. Setting the variable to null is only useful in special cases, such as:

  • long-lived objects that should drop references early
  • fields that might otherwise be reused accidentally
  • large object graphs where breaking references has a measurable effect

In ordinary local-variable code, it is usually noise.

Classes That Do Not Implement IDisposable

If a type does not implement IDisposable, there is no Dispose() contract to call. In that case, normal garbage collection is the memory cleanup story.

Example:

csharp
StringBuilder builder = new StringBuilder();
builder.Append("hello");
builder = null;

This may make the object collectible sooner if no other references exist, but in most code it is unnecessary. The runtime already handles short-lived managed objects well.

Finalizers Are Not a Substitute

Some types have finalizers, but you should not treat those as a replacement for Dispose(). Finalizers run nondeterministically and add GC overhead. They are a backup mechanism, not the preferred lifecycle model for ordinary consumer code.

If a type implements IDisposable, your code should generally dispose it explicitly.

A Practical Rule of Thumb

Ask two questions:

  1. does the type implement IDisposable
  2. does it own scarce or unmanaged resources

If the answer is yes, dispose it. If the object is just managed memory with no disposal contract, setting it to null is usually unnecessary unless you have a specific profiling-backed reason.

That is the pragmatic line. Most everyday C# code should focus on using and resource ownership, not on manual nulling.

Common Pitfalls

The most common mistake is assuming obj = null closes files, network sockets, or database connections. It does not.

Another issue is calling Dispose() and then continuing to use the object. Disposed objects are often in an invalid state and may throw exceptions.

Developers also sometimes sprinkle = null assignments everywhere in managed code as if that improves performance automatically. In most cases, it just adds noise and makes ownership less clear.

Finally, do not skip Dispose() because "the GC will handle it." The GC handles memory. Dispose() handles timely resource release.

Summary

  • Setting a reference to null removes one reference; it does not destroy the object immediately.
  • 'Dispose() releases resources deterministically for IDisposable types.'
  • Use using or using declarations for the normal cleanup pattern in C#.
  • Setting a variable to null after disposal is usually unnecessary.
  • For resource-owning types, Dispose() matters far more than manual null assignment.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.