Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/standard/garbage-collection/implementing-dispose.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ All non-sealed classes (or Visual Basic classes not modified as `NotInheritable`

### Base class with managed resources

Here's a general example of implementing the dispose pattern for a base class that only owns managed resources.
Here's a general example of implementing the dispose pattern for a base class that only owns managed resources. The example uses <xref:System.Threading.Interlocked.CompareExchange%2A?displayProperty=nameWithType> to ensure thread-safe disposal.

:::code language="csharp" source="../../../samples/snippets/csharp/VS_Snippets_CLR_System/system.idisposable/cs/base1.cs":::
:::code language="vb" source="../../../samples/snippets/visualbasic/VS_Snippets_CLR_System/system.idisposable/vb/base1.vb":::
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;
using System.IO;
using System.Threading;

public class DisposableBase : IDisposable
{
// Detect redundant Dispose() calls.
private bool _isDisposed;
// 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();
Expand All @@ -19,10 +22,10 @@ public void Dispose()
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
// 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)
{
_isDisposed = true;

if (disposing)
{
// Dispose managed state.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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.
Expand All @@ -27,8 +28,10 @@ public static LocalAllocHandle Allocate(int numberOfBytes)

public class DisposableBaseWithSafeHandle : IDisposable
{
// Detect redundant Dispose() calls.
private bool _isDisposed;
// 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);
Expand All @@ -44,10 +47,10 @@ public void Dispose()
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
// 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)
{
_isDisposed = true;

if (disposing)
{
// Dispose managed state.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
Imports System.IO
Imports System.Threading

Public Class DisposableBase
Implements IDisposable

' Detect redundant Dispose() calls.
Private _isDisposed As Boolean
' 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()
Expand All @@ -17,9 +20,9 @@ Public Class DisposableBase

' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True

' 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()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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.
Expand Down Expand Up @@ -29,8 +30,10 @@ End Class
Public Class DisposableBaseWithSafeHandle
Implements IDisposable

' Detect redundant Dispose() calls.
Private _isDisposed As Boolean
' 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)
Expand All @@ -44,9 +47,9 @@ Public Class DisposableBaseWithSafeHandle

' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True

' 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()
Expand Down