As Dispose() and finalizers are aimed to different purposes, a class managing external memory-heavy resources should implement both of them. The consequence is writing the class so that it handles well two possible scenarios:
One solution is writing the cleanup code in such a way that running it once or twice would produce the same result as running it only once. Feasibility depends on the nature of the cleanup, for instance:
A safer solution is ensuring by design that the cleanup code is called once and only once whatever the external context. This can be achieved the "classic way" using a dedicated flag:
public class DisposableFinalizable1: IDisposable { private bool disposed = false; ~DisposableFinalizable1() { Cleanup(); } public void Dispose() { Cleanup(); } private void Cleanup() { if(!disposed) { // Actual code to release resources gets here, then disposed = true; } } } Alternately, the Garbage Collector provides a specific method SuppressFinalize() that allows skipping the finalizer after Dispose has been invoked:
public class DisposableFinalizable2 : IDisposable { ~DisposableFinalizable2() { Cleanup(); } public void Dispose() { Cleanup(); GC.SuppressFinalize(this); } private void Cleanup() { // Actual code to release resources gets here } }