This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Download Microsoft Edge
More info about Internet Explorer and Microsoft Edge
The
Dispose
method is primarily implemented to release unmanaged resources. When working with instance members that are
IDisposable
implementations, it's common to cascade
Dispose
calls. There are other reasons for implementing
Dispose
, for example, to free memory that was allocated, remove an item that was added to a collection, or signal the release of a lock that was acquired.
The
.NET garbage collector
doesn't allocate or release unmanaged memory. The pattern for disposing an object, referred to as the dispose pattern, imposes order on the lifetime of an object. The dispose pattern is used for objects that implement the
IDisposable
interface. This pattern is common when interacting with file and pipe handles, registry handles, wait handles, or pointers to blocks of unmanaged memory, because the garbage collector is unable to reclaim unmanaged objects.
To help ensure that resources are always cleaned up appropriately, a
Dispose
method should be idempotent, such that it's callable multiple times without throwing an exception. Furthermore, subsequent invocations of
Dispose
should do nothing.
The code example provided for the
GC.KeepAlive
method shows how garbage collection can cause a finalizer to run while an unmanaged reference to the object or its members is still in use. It may make sense to utilize
GC.KeepAlive
to make the object ineligible for garbage collection from the start of the current routine to the point where this method is called.
With regard to dependency injection, when registering services in an
IServiceCollection
, the
service lifetime
is managed implicitly on your behalf. The
IServiceProvider
and corresponding
IHost
orchestrate resource cleanup. Specifically, implementations of
IDisposable
and
IAsyncDisposable
are properly disposed at the end of their specified lifetime.
For more information, see
Dependency injection in .NET
.
Safe handles
Writing code for an object's finalizer is a complex task that can cause problems if not done correctly. Therefore, we recommend that you construct
System.Runtime.InteropServices.SafeHandle
objects instead of implementing a finalizer.
A
System.Runtime.InteropServices.SafeHandle
is an abstract managed type that wraps an
System.IntPtr
that identifies an unmanaged resource. On Windows it might identify a handle, and on Unix, a file descriptor. The
SafeHandle
provides all of the logic necessary to ensure that this resource is released once and only once, either when the
SafeHandle
is disposed of or when all references to the
SafeHandle
have been dropped and the
SafeHandle
instance is finalized.
The
System.Runtime.InteropServices.SafeHandle
is an abstract base class. Derived classes provide specific instances for different kinds of handle. These derived classes validate what values for the
System.IntPtr
are considered invalid and how to actually free the handle. For example,
SafeFileHandle
derives from
SafeHandle
to wrap
IntPtrs
that identify open file handles/descriptors, and overrides its
SafeHandle.ReleaseHandle()
method to close it (via the
close
function on Unix or
CloseHandle
function on Windows). Most APIs in .NET libraries that create an unmanaged resource wraps it in a
SafeHandle
and return that
SafeHandle
to you as needed, rather than handing back the raw pointer. In situations where you interact with an unmanaged component and get an
IntPtr
for an unmanaged resource, you can create your own
SafeHandle
type to wrap it. As a result, few non-
SafeHandle
types need to implement finalizers. Most disposable pattern implementations only end up wrapping other managed resources, some of which may be
SafeHandle
objects.
The following derived classes in the
Microsoft.Win32.SafeHandles
namespace provide safe handles.
Class
Resources it holds
SafeFileHandle
SafeMemoryMappedFileHandle
SafePipeHandle
Files, memory mapped files, and pipes
SafeMemoryMappedViewHandle
Memory views
SafeNCryptKeyHandle
SafeNCryptProviderHandle
SafeNCryptSecretHandle
Cryptography constructs
SafeRegistryHandle
Registry keys
SafeWaitHandle
Wait handles
Dispose() and Dispose(bool)
The
IDisposable
interface requires the implementation of a single parameterless method,
Dispose
. Also, any non-sealed class should have an
Dispose(bool)
overload method.
Method signatures are:
public
non-virtual (
NotOverridable
in Visual Basic) (
IDisposable.Dispose
implementation).
protected virtual
(
Overridable
in Visual Basic)
Dispose(bool)
.
The Dispose() method
Because the
public
, non-virtual (
NotOverridable
in Visual Basic), parameterless
Dispose
method is called when it's no longer needed (by a consumer of the type), its purpose is to free unmanaged resources, perform general cleanup, and to indicate that the finalizer, if one is present, doesn't have to run. Freeing the actual memory associated with a managed object is always the domain of the
garbage collector
. Because of this, it has a standard implementation:
public void Dispose()
// Dispose of unmanaged resources.
Dispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
Public Sub Dispose() _
Implements IDisposable.Dispose
' Dispose of unmanaged resources.
Dispose(True)
' Suppress finalization.
GC.SuppressFinalize(Me)
End Sub
The
Dispose
method performs all object cleanup, so the garbage collector no longer needs to call the objects'
Object.Finalize
override. Therefore, the call to the
SuppressFinalize
method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to
GC.SuppressFinalize
has no effect. The actual cleanup is performed by the
Dispose(bool)
method overload.
The Dispose(bool) method overload
In the overload, the
disposing
parameter is a
Boolean
that indicates whether the method call comes from a
Dispose
method (its value is
true
) or from a finalizer (its value is
false
).
protected virtual void Dispose(bool disposing)
if (_disposed)
return;
if (disposing)
// TODO: dispose managed state (managed objects).
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposed = true;
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Exit Sub
' A block that frees unmanaged resources.
If disposing Then
' Deterministic call…
' A conditional block that frees managed resources.
End If
disposed = True
End Sub
Important
The
disposing
parameter should be
false
when called from a finalizer, and
true
when called from the
IDisposable.Dispose
method. In other words, it is
true
when deterministically called and
false
when non-deterministically called.
The body of the method consists of three blocks of code:
A block for conditional return if object is already disposed.
A block that frees unmanaged resources. This block executes regardless of the value of the
disposing
parameter.
A conditional block that frees managed resources. This block executes if the value of
disposing
is
true
. The managed resources that it frees can include:
Managed objects that implement
IDisposable
.
The conditional block can be used to call their
Dispose
implementation (cascade dispose). If you have used a derived class of
System.Runtime.InteropServices.SafeHandle
to wrap your unmanaged resource, you should call the
SafeHandle.Dispose()
implementation here.
Managed objects that consume large amounts of memory or consume scarce resources.
Assign large managed object references to
null
to make them more likely to be unreachable. This releases them faster than if they were reclaimed nondeterministically.
If the method call comes from a finalizer, only the code that frees unmanaged resources should execute. The implementer is responsible for ensuring that the false path doesn't interact with managed objects that may have been disposed. This is important because the order in which the garbage collector disposes managed objects during finalization is nondeterministic.
Cascade dispose calls
If your class owns a field or property and its type implements
IDisposable
, the containing class itself should also implement
IDisposable
. A class that instantiates an
IDisposable
implementation and stores it as an instance member is also responsible for its cleanup. This helps ensure that the referenced disposable types are given the opportunity to deterministically perform cleanup through the
Dispose
method. In the following example, the class is
sealed
(or
NotInheritable
in Visual Basic).
using System;
public sealed class Foo : IDisposable
private readonly IDisposable _bar;
public Foo()
_bar = new Bar();
public void Dispose() => _bar.Dispose();
Public NotInheritable Class Foo
Implements IDisposable
Private ReadOnly _bar As IDisposable
Public Sub New()
_bar = New Bar()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
_bar.Dispose()
End Sub
End Class
If your class has an
IDisposable
field or property but doesn't
own
it, meaning the class doesn't create the object, then the class doesn't need to implement
IDisposable
.
There are cases when you may want to perform
null
-checking in a finalizer (which includes the
Dispose(false)
method invoked by a finalizer). One of the primary reasons is if you're unsure whether the instance got fully initialized (for example, an exception might be thrown in a constructor).
Implement the dispose pattern
All non-sealed classes (or Visual Basic classes not modified as
NotInheritable
) should be considered a potential base class, because they could be inherited. If you implement the dispose pattern for any potential base class, you must provide the following:
A
Dispose
implementation that calls the
Dispose(bool)
method.
A
Dispose(bool)
method that performs the actual cleanup.
Either a class derived from
SafeHandle
that wraps your unmanaged resource (recommended), or an override to the
Object.Finalize
method. The
SafeHandle
class provides a finalizer, so you don't have to write one yourself.
Important
It's possible for a base class to only reference managed objects and implement the dispose pattern. In these cases, a finalizer is unnecessary. A finalizer is only required if you directly reference unmanaged resources.
Here's a general example of implementing the dispose pattern for a base class that uses a safe handle.
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
public class BaseClassWithSafeHandle : IDisposable
// To detect redundant calls
private bool _disposedValue;
// Instantiate a SafeHandle instance.
private SafeHandle? _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
Dispose(true);
GC.SuppressFinalize(this);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
_safeHandle?.Dispose();
_safeHandle = null;
_disposedValue = true;
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Public Class BaseClassWithSafeHandle
Implements IDisposable
' To detect redundant calls
Private _disposedValue As Boolean
' Instantiate a SafeHandle instance.
Private _safeHandle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
_safeHandle?.Dispose()
_safeHandle = Nothing
End If
_disposedValue = True
End If
End Sub
End Class
The previous example uses a
SafeFileHandle
object to illustrate the pattern; any object derived from
SafeHandle
could be used instead. Note that the example does not properly instantiate its
SafeFileHandle
object.
Here's the general pattern for implementing the dispose pattern for a base class that overrides
Object.Finalize
.
using System;
public class BaseClassWithFinalizer : IDisposable
// To detect redundant calls
private bool _disposedValue;
~BaseClassWithFinalizer() => Dispose(false);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
Dispose(true);
GC.SuppressFinalize(this);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
// TODO: dispose managed state (managed objects)
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
_disposedValue = true;
Public Class BaseClassWithFinalizer
Implements IDisposable
' To detect redundant calls
Private _disposedValue As Boolean
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects)
End If
' TODO free unmanaged resources (unmanaged objects) And override finalizer
' TODO: set large fields to null
_disposedValue = True
End If
End Sub
End Class
In C#, you implement a finalization by providing a
finalizer
, not by overriding
Object.Finalize
. In Visual Basic, you create a finalizer with
Protected Overrides Sub Finalize()
.
Implement the dispose pattern for a derived class
A class derived from a class that implements the
IDisposable
interface shouldn't implement
IDisposable
, because the base class implementation of
IDisposable.Dispose
is inherited by its derived classes. Instead, to clean up a derived class, you provide the following:
A
protected override void Dispose(bool)
method that overrides the base class method and performs the actual cleanup of the derived class. This method must also call the
base.Dispose(bool)
(
MyBase.Dispose(bool)
in Visual Basic) method passing it the disposing status (
bool disposing
parameter) as an argument.
Either a class derived from
SafeHandle
that wraps your unmanaged resource (recommended), or an override to the
Object.Finalize
method. The
SafeHandle
class provides a finalizer that frees you from having to code one. If you do provide a finalizer, it must call the
Dispose(bool)
overload with
false
argument.
Here's an example of the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
public class DerivedClassWithSafeHandle : BaseClassWithSafeHandle
// To detect redundant calls
private bool _disposedValue;
// Instantiate a SafeHandle instance.
private SafeHandle? _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
_safeHandle?.Dispose();
_safeHandle = null;
_disposedValue = true;
// Call base class implementation.
base.Dispose(disposing);
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Public Class DerivedClassWithSafeHandle
Inherits BaseClassWithSafeHandle
' To detect redundant calls
Private _disposedValue As Boolean
' Instantiate a SafeHandle instance.
Private _safeHandle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
_safeHandle?.Dispose()
_safeHandle = Nothing
End If
_disposedValue = True
End If
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
The previous example uses a
SafeFileHandle
object to illustrate the pattern; any object derived from
SafeHandle
could be used instead. Note that the example does not properly instantiate its
SafeFileHandle
object.
Here's the general pattern for implementing the dispose pattern for a derived class that overrides
Object.Finalize
:
public class DerivedClassWithFinalizer : BaseClassWithFinalizer
// To detect redundant calls
private bool _disposedValue;
~DerivedClassWithFinalizer() => Dispose(false);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
// TODO: dispose managed state (managed objects).
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposedValue = true;
// Call the base class implementation.
base.Dispose(disposing);
Public Class DerivedClassWithFinalizer
Inherits BaseClassWithFinalizer
' To detect redundant calls
Private _disposedValue As Boolean
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
' TODO free unmanaged resources (unmanaged objects) And override a finalizer below.
' TODO: set large fields to null.
_disposedValue = True
End If
' Call the base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
See also
Disposal of services
SuppressFinalize
IDisposable
IDisposable.Dispose
Microsoft.Win32.SafeHandles
System.Runtime.InteropServices.SafeHandle
Object.Finalize
Define and consume classes and structs (C++/CLI)
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:
https://aka.ms/ContentUserFeedback
.
Submit and view feedback for
This product