IDisposable and using
Release files, connections and native resources at the right moment with Dispose and using, and implement IDisposable in your own classes.
IDisposable.
public interface IDisposable{ void Dispose(); // "release your resources now"}The using statement
using (var conn = new SqlConnection(connectionString)){ conn.Open(); // … query …} // conn.Dispose() is called here, even if an exception was thrown // C# 8+: using declaration, disposed at the end of the enclosing blockusing var reader = new StreamReader("members.csv");string? header = reader.ReadLine();using statement is shorthand for try { … } finally { obj?.Dispose(); }. If a type implements IDisposable, use it inside using unless something else owns it.
Implementing IDisposable
public sealed class RenderBuffer : IDisposable{ private IntPtr _gpuHandle; // a native resource private readonly FileStream _log; // a managed disposable we own private bool _disposed; public RenderBuffer(string logPath) { _gpuHandle = NativeGpu.Allocate(1024 * 1024); _log = File.OpenWrite(logPath); } public void Draw() { ObjectDisposedException.ThrowIf(_disposed, this); // .NET 7+ // … use the buffer … } public void Dispose() { if (_disposed) return; // safe to call twice NativeGpu.Free(_gpuHandle); _gpuHandle = IntPtr.Zero; _log.Dispose(); // dispose what you own _disposed = true; }}Dispose everything your object owns that is disposable. Make Disposesafe to call more than once.After disposal, throw ObjectDisposedExceptionif someone uses the object.For non-sealed classes with native resources, look up the full “dispose pattern” with protected virtual void Dispose(bool disposing)and a finalizer, or better, wrap the handle in aSafeHandle.
IAsyncDisposable
await using var stream = new FileStream("big.bin", FileMode.Create);await stream.WriteAsync(data);Timer3D : IDisposable that starts a Stopwatch in its constructor and, in Dispose, prints “<name> took X ms”. Use it with using around a loop that sums 1 to 10 million, so the time is printed automatically at the end of the block.
Show the solution
using System.Diagnostics; using (new Timer3D("Sum loop")){ long sum = 0; for (int i = 1; i <= 10_000_000; i++) sum += i; Console.WriteLine(sum);} public sealed class Timer3D : IDisposable{ private readonly string _name; private readonly Stopwatch _sw = Stopwatch.StartNew(); public Timer3D(string name) => _name = name; public void Dispose() => Console.WriteLine($"{_name} took {_sw.ElapsedMilliseconds} ms");}50000005000000 Sum loop took 9 ms
Remember
IDisposable.Dispose()releases non-memory resources immediately.Always wrap disposable objects you create in using.using= try/finally with Dispose; it runs even on exceptions.Implement IDisposable when your class owns disposable or native resources.