Aracılığıyla paylaş


Dispose yöntemini uygulayın

Dispose yöntemi öncelikle yönetilmeyen kaynakları serbest bırakmak için uygulanır. IDisposable uygulamaları olan örnek üyelerle çalışılırken, genellikle Dispose çağrılarının basamaklaması gerçekleştirilir. Disposeuygulamasının başka nedenleri de vardır. Örneğin, ayrılan belleği boşaltmak, koleksiyona eklenmiş olan bir öğeyi kaldırmak veya alınan kilidin serbest bırakıldığının sinyalini vermek.

.NET çöp toplayıcı yönetilmeyen bellek ayırmaz veya serbest bırakmaz. Dispose pattern olarak adlandırılan bir nesneyi bertaraf etme deseni, bir nesnenin yaşam döngüsüne belirli bir düzen uygular. Dispose deseni, IDisposable arabirimini uygulayan nesneler için kullanılır. Çöp toplayıcı yönetilmeyen nesneleri geri kazanamadığından, dosya ve kanal tanıtıcıları, kayıt defteri tanıtıcıları, bekleme tutamaçları veya yönetilmeyen bellek bloklarına yönelik işaretçilerle etkileşim kurarken bu desen yaygın olarak görülür.

Kaynakların her zaman uygun şekilde temizlendiğinden emin olmak için, bir Dispose yöntemi, hata yaratmadan birden çok kez çağrılabilmesi için idempotent olmalıdır. Ayrıca, sonraki Dispose çağrıları hiçbir şey yapmamalıdır.

GC.KeepAlive yöntemi için sağlanan kod örneği, nesneye veya üyelerine yönelik yönetilmeyen bir referans hala kullanımdayken çöp toplamanın sonlandırıcının çalışmasına nasıl yol açabileceğini gösterir. Geçerli rutinin başlangıcından bu yöntemin çağrıldığı noktaya kadar nesneyi çöp toplamadan korumak için GC.KeepAlive kullanmak mantıklı olabilir.

Bahşiş

Bağımlılık ekleme bağlamında, hizmetleri bir IServiceCollectionkaydederken, hizmet ömrü sizin adınıza dolaylı olarak yönetilir. IServiceProvider ve karşılık gelen IHost kaynak temizlemeyi düzenler. Özellikle, IDisposable ve IAsyncDisposable uygulamaları belirtilen yaşam sürelerinin sonunda uygun şekilde temizlenir.

Daha fazla bilgi için bkz. .NET'te Bağımlılık Ekleme.

Art arda başlayarak atılan nesne temizleme çağrıları

Sınıfınız uygulayan IDisposablebaşka bir türün örneğine sahipse, içeren sınıfın da uygulaması IDisposablegerekir. Genellikle bir IDisposable uygulamanın örneğini oluşturan ve bunu örnek üyesi (veya özelliği) olarak depolayan bir sınıf da temizlemeden sorumludur. Bu, atıfta bulunulan tek kullanımlık türlerin Dispose yöntemiyle belirleyici bir şekilde temizlik yapma fırsatı elde etmesine yardımcı olur. Aşağıdaki örnekte, sınıf sealed'dır (veya Visual Basic'te NotInheritable'dir).

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

Bahşiş

  • Sınıfınızın bir IDisposable alanı veya özelliği varsa ancak buna sahip değilse, sınıfının uygulaması IDisposablegerekmez. Genellikle alt nesneyi oluşturan ve depo eden IDisposable bir sınıf da sahip olur, ancak bazı durumlarda sahiplik başka bir IDisposable türe aktarılabilir.
  • Sonlandırıcıda (sonlandırıcı tarafından çağrılan Dispose(false) yöntemini içeren) bir null denetimi gerçekleştirmek isteyebileceğiniz durumlar vardır. Temel nedenlerden biri, örneğin bir örneğin tam olarak başlatılıp başlatılmadığından emin değilseniz, mesela bir oluşturucuda bir istisna fırlatılabilir olmasıdır.

Dispose() ve Dispose(bool)

IDisposable arabirimi, Disposetek bir parametresiz yöntemin uygulanmasını gerektirir. Ayrıca, korumalı olmayan tüm sınıflar Dispose(bool) aşırı yükleme yöntemine sahip olmalıdır.

Yöntem imzaları şunlardır:

  • public sanal olmayan (Visual Basic'teNotOverridable) (IDisposable.Dispose uygulama).
  • protected virtual ( Visual Basic'teOverridable) Dispose(bool).

Dispose() yöntemi

public, sanal olmayan (Visual Basic'teNotOverridable), parametresiz Dispose yöntemi artık gerekli olmadığında türün tüketicisi tarafından çağrılır; amacı yönetilmeyen kaynakları serbest bırakmak, genel bir temizlik yapmak ve, varsa, sonlandırıcının çalıştırılmasına gerek olmadığını belirtmektir. Yönetilen nesneyle ilişkili gerçek belleği boşaltmak her zaman çöp toplayıcıetki alanıdır. Bu nedenle standart bir uygulaması vardır:

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

Dispose yöntemi tüm nesne temizleme işlemlerini gerçekleştirir, bu nedenle atık toplayıcının artık nesnelerin Object.Finalize geçersiz kılmasını çağırması gerekmez. Bu nedenle, SuppressFinalize yöntemine yapılan çağrı, çöp toplayıcının sonlandırıcıyı çalıştırmasını engeller. Türün sonlandırıcısı yoksa, GC.SuppressFinalize çağrısının hiçbir etkisi olmaz. Gerçek temizleme, Dispose(bool) yöntemi aşırı yüklemesi tarafından gerçekleştirilir.

bool parametresi ile Dispose yöntemi aşırı yüklemesi

Aşırı yüklemede, disposing parametresi, yöntem çağrısının bir Boolean yönteminden mi (değeri Dispose) yoksa sonlandırıcıdan mı geldiğini (değeri true) gösteren bir false.

protected virtual void Dispose(bool disposing)
{
    if (_disposed)
    {
        return;
    }

    if (disposing)
    {
        // Dispose managed state (managed objects).
        // ...
    }

    // Free unmanaged resources.
    // ...

    _disposed = true;
}
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

Önemli

disposing parametresi, sonlandırıcıdan çağrıldığında false olmalıdır ve true yönteminden çağrıldığında IDisposable.Dispose olmalıdır. Başka bir deyişle, deterministik olarak çağrıldığında true ve deterministik olmayan bir şekilde çağrıldığında false.

yönteminin gövdesi üç kod bloğundan oluşur:

  • Nesnenin zaten bertaraf edilmiş olması durumunda koşullu dönüş için bir blok.

  • Yönetilen kaynakları serbest getiren koşullu bir blok. disposing değeri trueise bu blok yürütülür. Serbest bıraktığı yönetilen kaynaklar şunları içerebilir:

    • IDisposableuygulayan yönetilen nesneler. Koşullu blok, Dispose uygulamasını çağırmak için kullanılabilir (zincirleme imha). Yönetilmeyen kaynağınızı sarmak için türetilmiş bir System.Runtime.InteropServices.SafeHandle sınıfı kullandıysanız, SafeHandle.Dispose() uygulamasını burada çağırmalısınız.
    • Büyük miktarda bellek kullanan veya az miktarda kaynak tüketen yönetilen nesneler. Ulaşılamaz hale gelme olasılıklarını artırmak için büyük yönetilen nesne referanslarını null'a atayın. Bu, onları belirsiz bir şekilde geri kazanılmaları durumunda olduğundan daha hızlı serbest bırakır.
  • Yönetilmeyen kaynakları serbest getiren bir blok. Bu blok, disposing parametresinin değerinden bağımsız olarak yürütülür.

Yöntem çağrısı bir sonlandırıcıdan geliyorsa, yalnızca yönetilmeyen kaynakları serbest getiren kodun yürütülmesi gerekir. Uygulayıcı, yanlış yolun imha edilmiş olabilecek yönetilen objelerle etkileşime girmediğinden emin olmakla sorumludur. Bu önemlidir çünkü sonlandırma sırasında çöp toplayıcının yönetilen nesneleri atma sırası belirsiz değildir.

Dispose desenini uygulama

Tüm korumalı olmayan sınıflar (veya NotInheritableolarak değiştirilmeyen Visual Basic sınıfları) devralınabilecekleri için olası bir temel sınıf olarak kabul edilmelidir. Olası herhangi bir temel sınıf için dispose desenini uygularsanız sınıfınıza aşağıdaki yöntemleri eklemeniz gerekir:

  • Dispose yöntemini çağıran bir Dispose(bool) uygulaması.
  • Gerçek temizliği gerçekleştiren bir Dispose(bool) yöntemi.
  • Sınıfınız yönetilmeyen kaynaklarla ilgileniyorsa, Object.Finalize yöntemini geçersiz kılmayı uyarlayın veya yönetilmeyen kaynağı SafeHandle ile sarmalayın.

Önemli

Sonlandırıcı ( Object.Finalize geçersiz kılma) yalnızca yönetilmeyen kaynaklara doğrudan başvuruyorsanız gereklidir. Bu, genellikle önlenebilen son derece gelişmiş bir senaryodur:

  • Sınıfınız yalnızca yönetilen nesnelere başvuruda bulunursa, sınıfın dispose desenini uygulaması yine de mümkündür. Sonlandırıcı uygulamaya gerek yoktur.
  • Yönetilmeyen kaynaklarla ilgilenmeniz gerekiyorsa, yönetilmeyen tanıtıcıyı bir içine sarmanızı kesinlikle öneririz. , SafeHandle kendiniz yazmanız gerekmeyecek şekilde bir sonlandırıcı sağlar. Daha fazla bilgi için Bkz. Güvenli tanıtıcılar paragrafı.

Yönetilen kaynaklara sahip temel sınıf

Aşağıda yalnızca yönetilen kaynaklara sahip olan bir temel sınıf için dispose deseninin uygulanmasına yönelik genel bir örnek verilmiştir.

using System;
using System.IO;

public class DisposableBase : IDisposable
{
    // Detect redundant Dispose() calls.
    private bool _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)
    {
        if (!_isDisposed)
        {
            _isDisposed = true;

            if (disposing)
            {
                // Dispose managed state.
                _managedResource?.Dispose();
                _managedResource = null;
            }
        }
    }
}
Imports System.IO

Public Class DisposableBase
    Implements IDisposable

    ' Detect redundant Dispose() calls.
    Private _isDisposed As Boolean

    ' 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)
        If Not _isDisposed Then
            _isDisposed = True

            If disposing Then
                ' Dispose managed state.
                _managedResource?.Dispose()
                _managedResource = Nothing
            End If
        End If
    End Sub
End Class

Not

Önceki örnekte deseni göstermek için sahteMemoryStream bir nesne kullanılır. Bunun yerine herhangi biri IDisposable kullanılabilir.

Yönetilmeyen (sistem yönetimi dışı) kaynaklarla temel sınıf

Temel sınıfın sahibi olduğu yönetilmeyen kaynakları temizlemek için Object.Finalize yöntemini geçersiz kılan bir durumda, dispose desenini uygulamaya yönelik bir örnek aşağıda verilmiştir. Örnek ayrıca iş parçacığı açısından güvenli bir şekilde Dispose(bool) uygulamanın bir yolunu gösterir. Yönetilmeyen kaynaklarla ilgilenirken çok iş parçacıklı uygulamalarda eşitleme kritik olabilir. Daha önce belirtildiği gibi, bu gelişmiş bir senaryodur.

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);
        }
    }
}
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 Class

Not

  • Önceki örnek, oluşturucuda yönetilmeyen yığında 10 bayt ayırmak için AllocHGlobal kullanır ve FreeHGlobal çağrısını yaparak Dispose(bool) içindeki arabelleği boşaltır. Bu, gösterim amacıyla yapılan bir sahte tahsistir.
  • Yine sonlandırıcı uygulamaktan kaçınmanızı öneririz. Önceki örneğin belirleyici olmayan sonlandırma ve eşitlemeyi SafeHandle öğesine devreden eşdeğeri için, Özel bir güvenli tanıtıcı kullanarak atma desenini uygulama başlığına bakın.

Bahşiş

C# dilinde, geçersiz kılarak değil, Object.Finalizesonlandırıcı sağlayarak bir sonlandırma uygularsınız. Visual Basic'te, Protected Overrides Sub Finalize()ile bir sonlandırıcı oluşturursunuz.

Türetilmiş bir sınıf için dispose desenini uygulama

IDisposable arabirimini uygulayan bir sınıftan türetilen bir sınıf, IDisposable temel sınıf uygulaması türetilmiş sınıfları tarafından devralındığından IDisposable.Disposeuygulamamalıdır. Bunun yerine, türetilmiş bir sınıfı temizlemek için aşağıdakileri sağlarsınız:

  • Temel sınıf yöntemini geçersiz kılan ve türetilmiş sınıfın gerçek temizlemesini gerçekleştiren bir protected override void Dispose(bool) yöntemi. Bu yöntem ayrıca base.Dispose(bool) (Visual Basic'teMyBase.Dispose(bool)) yöntemini çağırarakbool disposing parametresi olan yok etme durumunu bağımsız değişken olarak geçirmelidir.
  • Yönetilmeyen kaynağınızı sarmalayan (önerilen) SafeHandle türetilmiş bir sınıf veya Object.Finalize yöntemine geçersiz kılma. SafeHandle sınıfı, kod oluşturmanızı engelleyen bir sonlandırıcı sağlar. Bir sonlandırıcı sağlarsanız, Dispose(bool) bağımsız değişkeniyle false aşırı yüklemesini çağırması gerekir.

Güvenli tanıtıcı kullanan türetilmiş bir sınıf için dispose desenini uygulamaya yönelik genel desenin bir örneği aşağıda verilmiştir:

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);
    }
}
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 Class

Not

Önceki örnekte deseni göstermek için bir SafeFileHandle nesnesi kullanılır; bunun yerine SafeHandle türetilmiş herhangi bir nesne kullanılabilir. Şunu unutmayın, örnekte SafeFileHandle nesnesi düzgün bir şekilde örneklenmemiştir.

Aşağıda, Object.Finalize'ı geçersiz kılan bir türetilmiş sınıf için dispose modelini uygulamanın genel deseni verilmiştir:

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);
    }
}
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 Class

Güvenli tutamaçlar

Bir nesnenin sonlandırıcısı için kod yazmak, doğru yapılmazsa sorunlara neden olabilecek karmaşık bir görevdir. Bu nedenle, sonlandırıcı uygulamak yerine System.Runtime.InteropServices.SafeHandle nesneleri oluşturmanızı öneririz.

System.Runtime.InteropServices.SafeHandle, System.IntPtr'i saran ve yönetilmeyen bir kaynağı tanımlayan soyut bir yönetilen türdür. Windows'ta bir tanıtıcı ve Unix'te bir dosya tanımlayıcısı tanımlayabilir. SafeHandle, SafeHandle imha edildiğinde veya SafeHandle ile ilgili tüm başvurular kaldırıldığında ve SafeHandle örneği sonlandırıldığında, bu kaynağın bir kez ve yalnızca bir kez yayınlandığından emin olmak için gereken tüm mantığı sağlar.

System.Runtime.InteropServices.SafeHandle soyut bir temel sınıftır. Türetilmiş sınıflar, farklı türdeki saplar için belirli örnekler sağlar. Bu türetilmiş sınıflar, System.IntPtr için hangi değerlerin geçersiz kabul edildiğini ve tanıtıcının nasıl serbest edileceğini doğrular. Örneğin, SafeFileHandle açık dosya tutamaklarını ve tanımlayıcılarını tanımlayan SafeHandle öğesini sarmak için IntPtrs öğesinden türetilir ve SafeHandle.ReleaseHandle() yöntemini, Unix'te close işlevi veya Windows'da CloseHandle işlevi aracılığıyla kapatmak için geçersiz kılar. .NET kitaplıklarındaki API'lerin çoğu, yönetilmeyen kaynakları ham işaretçiyi geri vermek yerine bir SafeHandle içinde sarar ve gerektiğinde bu SafeHandle'yi size döndürür. Yönetilmeyen bir bileşenle etkileşime geçtiğinizde ve yönetilmeyen bir kaynak için IntPtr aldığınızda, bu kaynağı sarmak için kendi SafeHandle türünüzü oluşturabilirsiniz. Sonuç olarak, az sayıdaSafeHandle olmayan türün sonlandırıcıları uygulaması gerekir. Çoğu geçici desen uygulaması, yalnızca diğer yönetilen kaynakları sarar ve bazılarının SafeHandle nesnesi olabileceğini belirtir.

Özel bir güvenli tanıtıcı kullanarak yok etme desenini uygulama

Aşağıdaki kod, bir SafeHandleuygulayarak yönetilmeyen kaynakların nasıl işleneceğini gösterir.

using System;
using System.IO;
using System.Runtime.InteropServices;
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.
    private bool _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)
    {
        if (!_isDisposed)
        {
            _isDisposed = true;

            if (disposing)
            {
                // Dispose managed state.
                _otherUnmanagedResource?.Dispose();
                _safeHandle?.Dispose();
                _otherUnmanagedResource = null;
                _safeHandle = null;
            }
        }
    }
}
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
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.
    Private _isDisposed As Boolean

    ' 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)
        If Not _isDisposed Then
            _isDisposed = True

            If disposing Then
                ' Dispose managed state.
                _otherUnmanagedResource?.Dispose()
                _safeHandle?.Dispose()
                _otherUnmanagedResource = Nothing
                _safeHandle = Nothing
            End If
        End If
    End Sub
End Class

Not

sınıfının davranışı DisposableBaseWithSafeHandleönceki örnekteki sınıfın davranışıylaDisposableBaseWithFinalizer eşdeğerdir, ancak burada belirtilen yaklaşım daha güvenlidir:

  • Sonlandırıcıyı uygulamaya gerek yoktur, çünkü SafeHandle sonlandırmayı halleder.
  • İş parçacığı güvenliğini garanti etmek için senkronizasyona gerek yoktur. Dispose uygulamasında bir yarış durumu olsa da, SafeHandle, SafeHandle.ReleaseHandle bunun yalnızca bir kez çağrıldığını garanti eder.

.NET'te yerleşik güvenli kollar

Microsoft.Win32.SafeHandles ad alanında aşağıdaki türetilmiş sınıflar güvenli tanıtıcılar sağlar.

Sınıf Barındırmış olduğu kaynaklar
SafeFileHandle
SafeMemoryMappedFileHandle
SafePipeHandle
Dosyalar, belleğe eşlenen dosyalar ve kanallar
SafeMemoryMappedViewHandle Bellek görünümleri
SafeNCryptKeyHandle
SafeNCryptProviderHandle
SafeNCryptSecretHandle
Şifreleme yapıları
SafeRegistryHandle Kayıt defteri anahtarları
SafeWaitHandle Bekleme tutamaçları

Ayrıca bkz.