Skip to content
Code quality Reviewed 2026-09-13

IDisposable Implement

What does this mean ?

IDisposable supplies deterministic cleanup. A class may need it because it directly owns an unmanaged resource or owns another disposable object. The correct pattern depends on ownership, inheritance and whether a finalizer is actually required.

What can happen ?

Missing disposal can retain handles or other limited resources. Disposing a borrowed object can break its real owner's work. Neither problem is established by a randomness example or by merely repeating IDisposable in a declaration.

Recommendation

Document ownership and make disposal safe to call more than once. A sealed wrapper around an owned managed disposable does not need the entire inheritable finalizer pattern. Use the documented virtual disposal pattern for extensible types and SafeHandle for unmanaged handles. Consider IAsyncDisposable when the resource requires asynchronous cleanup.

Sample Code

This constructor explicitly takes ownership of the supplied stream. The wrapper is not intended for concurrent disposal/use:

using System;
using System.IO;

public sealed class OwnedStream : IDisposable
{
    private readonly Stream stream;
    private bool disposed;

    public OwnedStream(Stream stream)
    {
        this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
    }

    public void Dispose()
    {
        if (disposed) return;
        stream.Dispose(); // An empty Dispose would leak ownership's cleanup.
        disposed = true;
    }
}

There is no finalizer because the owned Stream manages its own resource lifecycle.

Regression checks

Use a fake stream recording disposal. Dispose the wrapper twice and verify the stream is disposed once. Test a null constructor argument. Ensure callers do not continue using a resource after transferring ownership.

References