IDisposable
object disposal
.NET
C#
resource management

How does one tell if an IDisposable object reference is disposed?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In .NET, IDisposable does not include an IsDisposed property. That means you generally cannot ask arbitrary disposable objects whether they are disposed unless the type explicitly exposes that state. This is by design: disposal is a behavioral contract (Dispose()), not a universal introspection API.

So how do you "tell" if an object is disposed? In practice, you either track disposal in your own type, use safe usage patterns that avoid needing the check, or handle expected post-disposal exceptions for third-party types.

Core Sections

1. Implement explicit disposal tracking in your own classes

When you control the type, keep a private flag and guard public methods.

csharp
1using System;
2
3public sealed class ResourceHolder : IDisposable
4{
5    private bool _disposed;
6
7    public bool IsDisposed => _disposed;
8
9    public void DoWork()
10    {
11        ThrowIfDisposed();
12        // normal work
13    }
14
15    public void Dispose()
16    {
17        if (_disposed) return;
18        // release managed/unmanaged resources
19        _disposed = true;
20        GC.SuppressFinalize(this);
21    }
22
23    private void ThrowIfDisposed()
24    {
25        if (_disposed)
26            throw new ObjectDisposedException(nameof(ResourceHolder));
27    }
28}

This gives deterministic behavior and clear diagnostics.

2. Prefer usage patterns that avoid external disposal checks

For external objects, best practice is to scope lifetime with using and avoid cross-scope references.

csharp
1using (var stream = File.OpenRead(path))
2{
3    // use stream here only
4}
5// no further access

When disposal ownership is shared or asynchronous, wrap dependencies with clear ownership semantics (factory, lifetime scope, DI container) instead of asking runtime state repeatedly.

3. For foreign types, handle ObjectDisposedException

If type does not expose state and you cannot control lifecycle perfectly, catch expected disposal exceptions at boundary points.

csharp
1try
2{
3    socket.Send(buffer);
4}
5catch (ObjectDisposedException)
6{
7    _logger.LogDebug("Socket already disposed during shutdown path");
8}

Do not use exception handling as normal control flow in hot paths, but it is valid for race-prone shutdown paths.

4. Concurrency and thread-safety

Disposal checks can race with disposal in multithreaded code. A check like if (!IsDisposed) Use() is not atomic.

Safer approaches:

  • lock around both check and use,
  • use cancellation tokens to coordinate shutdown,
  • centralize disposal in one owner thread.
csharp
1private readonly object _gate = new();
2
3public void SafeUse()
4{
5    lock (_gate)
6    {
7        ThrowIfDisposed();
8        // use resources
9    }
10}
11
12public void Dispose()
13{
14    lock (_gate)
15    {
16        if (_disposed) return;
17        _disposed = true;
18    }
19}

Common Pitfalls

  • Assuming every IDisposable object can report disposal state via a common API.
  • Exposing IsDisposed but forgetting to enforce it in all public methods.
  • Performing non-atomic check-then-use patterns in concurrent code.
  • Catching broad exceptions instead of ObjectDisposedException for disposal-related paths.
  • Sharing disposable dependencies across scopes without clear ownership contracts.

Summary

There is no universal way to query disposal state for arbitrary IDisposable references. For your own types, track and enforce _disposed explicitly. For external types, structure code around ownership scopes and handle ObjectDisposedException where races are expected. Good lifetime design is more reliable than ad hoc disposal-state probing.

A reliable strategy in larger systems is to model disposal ownership explicitly. For example, repositories may own DB connections per request scope, while singletons should never own scoped disposables directly. Dependency injection containers can enforce lifetimes and reduce manual disposal checks spread across business logic. When disposal ownership is clear, the need to query "is disposed" often disappears naturally.

Testing disposal behavior is important as well. Add unit tests that assert methods throw ObjectDisposedException after Dispose() and that multiple dispose calls are safe (idempotent). For async-capable resources, consider IAsyncDisposable patterns and await using. These tests turn disposal semantics into enforceable contracts instead of informal assumptions.

Clear lifetime diagrams in architecture docs can eliminate many disposal-related bugs before code is written.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track 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.

Browse interview questions

All Rights Reserved.