The System.IDisposable.Dispose method is primarily implemented to release unmanaged resources. When working with instance members that are System.IDisposable implementations, it's common to cascade System.IDisposable.Dispose calls. There are other reasons for implementing System.IDisposable.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 System.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 System.IDisposable.Dispose method should be idempotent, such that it's callable multiple times without throwing an exception. Furthermore, subsequent invocations of System.IDisposable.Dispose should do nothing.
The code example provided for the System.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 System.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.
ms.topic: include ms.date: 04/07/2021 ms.custom: include
Cascade dispose calls
If your class owns an instance of another type that implements System.IDisposable, the containing class itself should also implement System.IDisposable. Typically a class that instantiates an System.IDisposable implementation and stores it as an instance member (or property) is also responsible for its cleanup. This helps ensure that the referenced disposable types are given the opportunity to deterministically perform cleanup through the System.IDisposable.Dispose method. In the following example, the class is sealed (or NotInheritable in Visual Basic).
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR/conceptual.disposable/cs/Foo.cs
using System;
public sealed class Foo : IDisposable
{
private readonly IDisposable _bar;
public Foo()
{
_bar = new Bar();
}
public void Dispose() => _bar.Dispose();
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR/conceptual.disposable/vb/Foo.vb
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 ClassDispose() and Dispose(bool)
The System.IDisposable interface requires the implementation of a single parameterless method, System.IDisposable.Dispose. Also, any non-sealed class should have an Dispose(bool) overload method.
Method signatures are:
publicnon-virtual (NotOverridablein Visual Basic) (System.IDisposable.Dispose implementation).protected virtual(Overridablein 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:
sample · csharpdocs/standard/garbage-collection/snippets/dispose-pattern/csharp/Disposable.csDispose
using System;
public class Disposable : IDisposable
{
private bool _disposed;
// <SnippetDispose>
public void Dispose()
{
// Dispose of unmanaged resources.
Dispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
}
// </SnippetDispose>
// <SnippetDisposeBool>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
// ...
}
// Free unmanaged resources.
// ...
_disposed = true;
}
// </SnippetDisposeBool>
}sample · vbdocs/standard/garbage-collection/snippets/dispose-pattern/vb/Disposable.vbDispose
Public Class Disposable : Implements IDisposable
Dim disposed As Boolean
' <SnippetDispose>
Public Sub Dispose() _
Implements IDisposable.Dispose
' Dispose of unmanaged resources.
Dispose(True)
' Suppress finalization.
GC.SuppressFinalize(Me)
End Sub
' </SnippetDispose>
' <SnippetDisposeBool>
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Exit Sub
If disposing Then
' Free managed resources.
' ...
End If
' Free unmanaged resources.
' ...
disposed = True
End Sub
' </SnippetDisposeBool>
End ClassThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' System.Object.Finalize override. Therefore, the call to the System.GC.SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to System.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 System.Boolean that indicates whether the method call comes from a System.IDisposable.Dispose method (its value is true) or from a finalizer (its value is false).
sample · csharpdocs/standard/garbage-collection/snippets/dispose-pattern/csharp/Disposable.csDisposeBool
using System;
public class Disposable : IDisposable
{
private bool _disposed;
// <SnippetDispose>
public void Dispose()
{
// Dispose of unmanaged resources.
Dispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
}
// </SnippetDispose>
// <SnippetDisposeBool>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
// ...
}
// Free unmanaged resources.
// ...
_disposed = true;
}
// </SnippetDisposeBool>
}sample · vbdocs/standard/garbage-collection/snippets/dispose-pattern/vb/Disposable.vbDisposeBool
Public Class Disposable : Implements IDisposable
Dim disposed As Boolean
' <SnippetDispose>
Public Sub Dispose() _
Implements IDisposable.Dispose
' Dispose of unmanaged resources.
Dispose(True)
' Suppress finalization.
GC.SuppressFinalize(Me)
End Sub
' </SnippetDispose>
' <SnippetDisposeBool>
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Exit Sub
If disposing Then
' Free managed resources.
' ...
End If
' Free unmanaged resources.
' ...
disposed = True
End Sub
' </SnippetDisposeBool>
End ClassThe body of the method consists of three blocks of code:
A block for conditional return if object is already disposed.
A conditional block that frees managed resources. This block executes if the value of
disposingistrue. The managed resources that it frees can include:- Managed objects that implement System.IDisposable. The conditional block can be used to call their System.IDisposable.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 System.Runtime.InteropServices.SafeHandle.Dispose implementation here.
- Managed objects that consume large amounts of memory or consume scarce resources. Assign large managed object references to
nullto make them more likely to be unreachable. This releases them faster than if they were reclaimed nondeterministically.
A block that frees unmanaged resources. This block executes regardless of the value of the
disposingparameter.
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.
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 add the following methods to your class:
- A System.IDisposable.Dispose implementation that calls the
Dispose(bool)method. - A
Dispose(bool)method that performs the actual cleanup. - If your class deals with unmanaged resources, either provide an override to the System.Object.Finalize method or wrap the unmanaged resource in a System.Runtime.InteropServices.SafeHandle.
Base class with managed resources
Here's a general example of implementing the dispose pattern for a base class that only owns managed resources. The example uses System.Threading.Interlocked.CompareExchange to ensure thread-safe disposal.
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/base1.cs
using System;
using System.IO;
using System.Threading;
public class DisposableBase : IDisposable
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// 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)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
if (disposing)
{
// Dispose managed state.
_managedResource?.Dispose();
_managedResource = null;
}
}
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base1.vb
Imports System.IO
Imports System.Threading
Public Class DisposableBase
Implements IDisposable
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed = 0 means Dispose(bool) has not been called yet.
' _isDisposed = 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' 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(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 Then
If disposing Then
' Dispose managed state.
_managedResource?.Dispose()
_managedResource = Nothing
End If
End If
End Sub
End ClassBase class with unmanaged resources
Here's an example for implementing the dispose pattern for a base class that overrides System.Object.Finalize in order to clean up unmanaged resources it owns. The example also demonstrates a way to implement Dispose(bool) in a thread-safe manner. Synchronization might be critical when dealing with unmanaged resources in a multi-threaded application. As mentioned earlier, this is an advanced scenario.
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/base2.cs
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
public class DisposableBaseWithFinalizer : IDisposable
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// A pointer to 10 bytes allocated on the unmanaged heap.
private IntPtr _unmanagedResource = Marshal.AllocHGlobal(10);
~DisposableBaseWithFinalizer() => 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)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
if (disposing)
{
_managedResource?.Dispose();
_managedResource = null;
}
Marshal.FreeHGlobal(_unmanagedResource);
}
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base2.vb
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Threading
Public Class DisposableBaseWithFinalizer
Implements IDisposable
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed == 0 means Dispose(bool) has not been called yet.
' _isDisposed == 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' A pointer to 10 bytes allocated on the unmanaged heap.
Private _unmanagedResource As IntPtr = Marshal.AllocHGlobal(10)
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(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 Then
If disposing Then
_managedResource?.Dispose()
_managedResource = Nothing
End If
Marshal.FreeHGlobal(_unmanagedResource)
End If
End Sub
End ClassImplement the dispose pattern for a derived class
A class derived from a class that implements the System.IDisposable interface shouldn't implement System.IDisposable, because the base class implementation of System.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 thebase.Dispose(bool)(MyBase.Dispose(bool)in Visual Basic) method passing it the disposing status (bool disposingparameter) as an argument. - Either a class derived from System.Runtime.InteropServices.SafeHandle that wraps your unmanaged resource (recommended), or an override to the System.Object.Finalize method. The System.Runtime.InteropServices.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 withfalseargument.
Here's an example of the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/derived1.cs
using System.IO;
public class DisposableDerived : DisposableBase
{
// To detect redundant calls
private bool _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
_isDisposed = true;
if (disposing)
{
_managedResource?.Dispose();
_managedResource = null;
}
}
// Call base class implementation.
base.Dispose(disposing);
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/derived1.vb
Imports System.IO
Public Class DisposableDerived
Inherits DisposableBase
' To detect redundant calls
Private _isDisposed As Boolean
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True
If disposing Then
_managedResource?.Dispose()
_managedResource = Nothing
End If
End If
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End ClassHere's the general pattern for implementing the dispose pattern for a derived class that overrides System.Object.Finalize:
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/derived2.cs
using System.Threading;
public class DisposableDerivedWithFinalizer : DisposableBaseWithFinalizer
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
~DisposableDerivedWithFinalizer() => Dispose(false);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
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.
}
// Call the base class implementation.
base.Dispose(disposing);
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/derived2.vb
Imports System.Threading
Public Class DisposableDerivedWithFinalizer
Inherits DisposableBaseWithFinalizer
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed == 0 means Dispose(bool) has not been called yet.
' _isDisposed == 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 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.
End If
' Call the base class implementation.
MyBase.Dispose(disposing)
End Sub
End ClassSafe 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, Microsoft.Win32.SafeHandles.SafeFileHandle derives from SafeHandle to wrap IntPtrs that identify open file handles and descriptors, and overrides its System.Runtime.InteropServices.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 wrap 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 might be SafeHandle objects.
Implement the dispose pattern using a custom safe handle
The following code demonstrates how to handle unmanaged resources by implementing a System.Runtime.InteropServices.SafeHandle.
sample · csharpsamples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/safe.cs
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;
// Wraps the IntPtr allocated by Marshal.AllocHGlobal() into a SafeHandle.
class LocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private LocalAllocHandle() : base(ownsHandle: true) { }
// No need to implement a finalizer - SafeHandle's finalizer will call ReleaseHandle for you.
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
// Allocate bytes with Marshal.AllocHGlobal() and wrap the result into a SafeHandle.
public static LocalAllocHandle Allocate(int numberOfBytes)
{
IntPtr nativeHandle = Marshal.AllocHGlobal(numberOfBytes);
LocalAllocHandle safeHandle = new LocalAllocHandle();
safeHandle.SetHandle(nativeHandle);
return safeHandle;
}
}
public class DisposableBaseWithSafeHandle : IDisposable
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
// Managed disposable objects owned by this class
private LocalAllocHandle? _safeHandle = LocalAllocHandle.Allocate(10);
private Stream? _otherUnmanagedResource = new MemoryStream();
// 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)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
if (disposing)
{
// Dispose managed state.
_otherUnmanagedResource?.Dispose();
_safeHandle?.Dispose();
_otherUnmanagedResource = null;
_safeHandle = null;
}
}
}
}sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/safe.vb
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.Win32.SafeHandles
' Wraps the IntPtr allocated by Marshal.AllocHGlobal() into a SafeHandle.
Public Class LocalAllocHandle
Inherits SafeHandleZeroOrMinusOneIsInvalid
Private Sub New()
MyBase.New(True)
End Sub
' No need to implement a finalizer - SafeHandle's finalizer will call ReleaseHandle for you.
Protected Overrides Function ReleaseHandle() As Boolean
Marshal.FreeHGlobal(handle)
Return True
End Function
' Allocate bytes with Marshal.AllocHGlobal() and wrap the result into a SafeHandle.
Public Shared Function Allocate(numberOfBytes As Integer) As LocalAllocHandle
Dim nativeHandle As IntPtr = Marshal.AllocHGlobal(numberOfBytes)
Dim safeHandle As New LocalAllocHandle()
safeHandle.SetHandle(nativeHandle)
Return safeHandle
End Function
End Class
Public Class DisposableBaseWithSafeHandle
Implements IDisposable
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed = 0 means Dispose(bool) has not been called yet.
' _isDisposed = 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
' Managed disposable objects owned by this class
Private _safeHandle As LocalAllocHandle = LocalAllocHandle.Allocate(10)
Private _otherUnmanagedResource As Stream = New MemoryStream()
' 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(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 Then
If disposing Then
' Dispose managed state.
_otherUnmanagedResource?.Dispose()
_safeHandle?.Dispose()
_otherUnmanagedResource = Nothing
_safeHandle = Nothing
End If
End If
End Sub
End ClassBuilt-in safe handles in .NET
The following derived classes in the Microsoft.Win32.SafeHandles namespace provide safe handles.
| Class | Resources it holds |
|---|---|
| Microsoft.Win32.SafeHandles.SafeFileHandle Microsoft.Win32.SafeHandles.SafeMemoryMappedFileHandle Microsoft.Win32.SafeHandles.SafePipeHandle |
Files, memory mapped files, and pipes |
| Microsoft.Win32.SafeHandles.SafeMemoryMappedViewHandle | Memory views |
| Microsoft.Win32.SafeHandles.SafeNCryptKeyHandle Microsoft.Win32.SafeHandles.SafeNCryptProviderHandle Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle |
Cryptography constructs |
| Microsoft.Win32.SafeHandles.SafeRegistryHandle | Registry keys |
| Microsoft.Win32.SafeHandles.SafeWaitHandle | Wait handles |