Dispose metodu uygulama

Yöntemi uygulamak, Dispose öncelikle yönetilmeyen kaynakların serbest bırakılması içindir. Uygulamalar olan örnek üyeleriyle çalışırken IDisposable , basamaklı Dispose çağrılar yaygındır. DisposeÖrneğin, ayrılan belleği serbest bırakma, koleksiyona eklenen bir öğeyi kaldırma veya alınan bir kilidin serbest bırakılması sinyali gibi nedenlerle başka nedenler de vardır.

.Net atık toplayıcısı , yönetilmeyen bellek ayırır veya serbest bırakmaz. Dispose düzeni olarak adlandırılan bir nesneyi elden atma düzeni, bir nesnenin kullanım ömrüne göre sıra uygular. Dispose deseninin, arabirimi uygulayan nesneler için kullanılır IDisposable ve dosya ve kanal tutamaçları, kayıt defteri tutamaçları, bekleme tutamaçları veya yönetilmeyen bellek bloklarına yönelik işaretçilerle etkileşim kurarken yaygındır. Bunun nedeni, çöp toplayıcının yönetilmeyen nesneleri geri kazanmamadır.

Kaynakların her zaman uygun şekilde temizlendiğinden emin olmak için bir Dispose Yöntem, özel durum oluşturmadan birden çok kez çağrılabilir şekilde ıdempotent olmalıdır. Ayrıca, sonraki çağırmaları Dispose hiçbir şey yapmaz.

Yöntemi için belirtilen kod örneği, GC.KeepAlive çöp toplamanın bir sonlandırıcının çalışmasına nasıl neden olabileceği, nesneye veya üyelerine yönetilmeyen bir başvuru hala kullanımda olduğunda gösterir. GC.KeepAliveNesneyi, geçerli yordamın başından bu yöntemin çağrıldığı noktaya kadar çöp toplama için uygun hale getirmek için kullanılması anlamlı olabilir.

İpucu

Bağımlılık ekleme ile ilgili olarak, Hizmetleri bir içinde kaydettirirken IServiceCollection hizmet ömrü sizin adınıza örtülü olarak yönetilir. IServiceProviderVe buna karşılık gelen IHost kaynak temizliği. Özellikle, ve uygulamaları IDisposable , IAsyncDisposable belirtilen yaşam sürelerinin sonuna doğru şekilde atıldı.

Daha fazla bilgi için bkz. .net 'e bağımlılık ekleme.

Kasa tutamaçları

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

System.Runtime.InteropServices.SafeHandle, Yönetilmeyen bir kaynağı tanımlayan bir soyut yönetilen türdür System.IntPtr . Windows, bir dosya tanımlayıcısı olan UNIX üzerinde bir tanıtıcıyı tanımlayabilir. Bu kaynağın bir kez ve yalnızca bir kez serbest bırakıldığını sağlamak için gereken tüm mantığı sağlar. Bu, ' nin ve ' a SafeHandle yapılan tüm başvurular SafeHandle atıldıktan sonra ve SafeHandle örnek sonlandırıldığında.

, System.Runtime.InteropServices.SafeHandle Soyut bir temel sınıftır. Türetilmiş sınıflar, farklı tanıtıcı türleri için belirli örnekler sağlar. Bu türetilmiş sınıflar, için hangi değerlerin System.IntPtr geçersiz kabul edildiği ve tanıtıcıyı gerçekten serbest bırakma işlemlerinin nasıl yapıldığını doğrular. Örneğin, SafeFileHandle SafeHandle IntPtrs Açık dosya tutamaçlarını/tanımlayıcılarını tanımlayan sarmadan türeyebilir ve SafeHandle.ReleaseHandle() bunu kapatmak için yöntemini geçersiz kılar ( close UNIX veya CloseHandle Windows işlevindeki işlev aracılığıyla). Yönetilmeyen bir kaynağı oluşturan .NET kitaplıklarında API 'Lerin çoğu, bunu bir içinde saracaktır SafeHandle ve SafeHandle ham işaretçiyi geri almak yerine size gerektiğinde döndürür. Yönetilmeyen bir bileşenle etkileşim kuran ve yönetilmeyen bir kaynak için kullanabileceğiniz durumlarda IntPtr , SafeHandle onu kaydırmak için kendi türünü de oluşturabilirsiniz. Sonuç olarak, SafeHandle bazı tür olmayan işlem sonlandırıcıları uygulamanız gerekir; çoğu atılabilir model uygulaması yalnızca diğer yönetilen kaynakların sarmalanması, bazıları bazı ' SafeHandle lar olabilir.

Ad alanındaki aşağıdaki türetilmiş sınıflar, Microsoft.Win32.SafeHandles güvenli işleyiciler sağlar:

Dispose () ve Dispose (bool)

IDisposableArabirim, tek parametresiz bir yöntemin uygulanmasını gerektirir Dispose . Ayrıca, korumalı olmayan herhangi bir sınıfın ek bir Dispose(bool) aşırı yükleme yöntemi olmalıdır.

Yöntem imzaları:

  • publicsanal olmayan ( NotOverridable Visual Basic) ( IDisposable.Dispose uygulama).
  • protected virtual( Overridable Visual Basic) Dispose(bool) .

Dispose () yöntemi

public, sanal olmayan ( NotOverridable Visual Basic), parametresiz Dispose yöntem artık gerekli olmadığında çağrılır (türü tüketicisinde), bu, yönetilmeyen kaynakları serbest bırakmak, genel temizlik yapmak ve bir sonlandırıcı varsa sonlandırıcının çalıştırması gerekmez. Yönetilen bir nesneyle ilişkili gerçek bellek boşaltılırken her zaman çöp toplayıcınınetki 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

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

Dispose (bool) yöntemi aşırı yüklemesi

Aşırı yüklemede disposing parametresi, Boolean yöntem çağrısının bir Dispose yöntemden (değer true ) mi yoksa sonlandırıcının mi (değer) geldiğini belirten bir ' dir 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

Önemli

disposingParametresi false bir Sonlandırıcı 'dan çağrıldığında ve true yönteminden çağrıldığında olmalıdır IDisposable.Dispose . Diğer bir deyişle, true belirleyici olmayan ve belirleyici olmayan bir şekilde false çağrılmayan bir değer.

Yöntemin gövdesi, üç kod blobundan oluşur:

  • Nesne zaten atıldığı takdirde koşullu dönüşte bir blok.

  • Yönetilmeyen kaynakları serbest bırakan bir blok. Bu blok, parametrenin değerinden bağımsız olarak yürütülür disposing .

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

    • Uygulayan yönetilen nesneler IDisposable . Koşullu blok, uygulamasını çağırmak için kullanılabilir Dispose (Cascade Dispose). Yönetilmeyen kaynağınızı kaydırmak için türetilmiş bir sınıf kullandıysanız System.Runtime.InteropServices.SafeHandle , SafeHandle.Dispose() uygulamayı buradan çağırmanız gerekir.

    • Büyük miktarlarda bellek kullanan veya nadir kaynaklarını tüketen yönetilen nesneler. ' A büyük yönetilen nesne başvuruları atayarak, null ulaşılamaz olma olasılığı yüksektir. Bu, bunları belirleyici olmayan şekilde geri kazanıladıklarından daha hızlı bırakır.

Yöntem çağrısı bir sonlandırıcının geliyorsa, yalnızca yönetilmeyen kaynakları serbest bırakma kodu yürütmelidir. Uygulayıcısı, yanlış yolun, geri kazanılabileceğini yönetilen nesnelerle etkileşimde olmamasını sağlamaktan sorumludur. Bu önemlidir çünkü çöp toplayıcının sonlandırma sırasında yönetilen nesneleri yok sayılamayan sıra belirleyici değildir.

Basamaklı atma çağrıları

Sınıfınız bir alan veya özelliğe sahipse ve türü uygularsa IDisposable , kapsayan sınıfın kendisi de uygulamalıdır IDisposable . Bir uygulamayı örnekleyen IDisposable ve örnek üye olarak depolayan bir sınıf, temizlemeden de sorumludur. Bu, başvurulan atılabilir türlerine, yöntemi aracılığıyla temizleme işlemini kesin bir şekilde gerçekleştirmek için fırsat verilmesini sağlamaya yardımcı olur Dispose . Bu örnekte, sınıfı sealed (veya NotInheritable 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

Dispose modelini uygulama

korumalı olmayan tüm sınıfların (veya Visual Basic sınıfları NotInheritable ), devralınabileceğinden, olası bir temel sınıf olarak düşünülmelidir. Herhangi bir olası temel sınıf için Dispose modelini uygularsanız, aşağıdakileri sağlamalısınız:

  • DisposeYöntemini çağıran bir uygulama Dispose(bool) .
  • Dispose(bool)Gerçek temizleme işlemini gerçekleştiren bir yöntem.
  • Öğesinden türetilen bir sınıf SafeHandle , Yönetilmeyen kaynağınızı sarmalanmış (önerilir) veya yöntemine bir geçersiz kılma Object.Finalize . SafeHandleSınıfı bir Sonlandırıcı sağlar, bu nedenle kendiniz yazmak zorunda değilsiniz.

Önemli

Temel sınıfın yalnızca yönetilen nesnelere başvurması ve Dispose deseninin uygulanması mümkündür. Bu durumlarda, sonlandırıcısı gereksizdir. Sonlandırıcı yalnızca yönetilmeyen kaynaklara doğrudan başvurdıysanız gereklidir.

Aşağıda, güvenli tanıtıcı kullanan bir temel sınıf için Dispose deseninin uygulanması için genel bir düzene örnek verilmiştir.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

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

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposedValue)
        {
            if (disposing)
            {
                _safeHandle.Dispose();
            }

            _disposedValue = true;
        }
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class BaseClassWithSafeHandle : Implements IDisposable
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False
    ' Instantiate a SafeHandle instance.
    Dim handle 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(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            handle.Dispose()
        End If

        disposed = True
    End Sub
End Class

Not

Önceki örnek, bir SafeFileHandle nesneyi göstermek için bir nesnesi kullanır; bunun yerine ondan türetilmiş herhangi bir nesne SafeHandle kullanılabilir. Örneğin nesnesinin düzgün şekilde örneklemez olduğunu unutmayın SafeFileHandle .

Geçersiz kılan bir temel sınıf için Dispose deseninin uygulanması için genel bir model Object.Finalize .

using System;

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;
        }
    }
}
Class BaseClassWithFinalizer : Implements IDisposable
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False

    ' 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 disposed Then Return

        If disposing Then
            ' Dispose managed objects that implement IDisposable.
            ' Assign null to managed objects that consume large amounts of memory or consume scarce resources.
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(False)
    End Sub
End Class

İpucu

C# ' ta, geçersiz kılarak değil, sonlandırıcısısağlayarak bir sonlandırma uygulamaktır Object.Finalize . Visual Basic, ile bir sonlandırıcısı oluşturursunuz Protected Overrides Sub Finalize() .

Türetilmiş bir sınıf için Dispose modelini uygulama

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

  • protected override void Dispose(bool)Temel sınıf yöntemini geçersiz kılan ve türetilmiş sınıfın gerçek temizleme işlemini gerçekleştiren bir yöntem. bu yöntem ayrıca, base.Dispose(bool) MyBase.Dispose(bool) bir bağımsız değişken olarak disposing durumu (parametre) geçirerek (Visual Basic olarak) metodunu çağırmalıdır bool disposing .
  • Öğesinden türetilen bir sınıf SafeHandle , Yönetilmeyen kaynağınızı sarmalanmış (önerilir) veya yöntemine bir geçersiz kılma Object.Finalize . SafeHandleSınıfı, sizi kod içine almak zorunda kalmanızı sağlayan bir Sonlandırıcı sağlar. Bir Sonlandırıcı sağlarsanız, Dispose(bool) bağımsız değişkenle aşırı yüklemeyi çağırmalıdır false .

Aşağıda, bir güvenli tanıtıcı kullanan türetilmiş bir sınıf için Dispose deseninin uygulanması için genel bir düzenin örneği verilmiştir:

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

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

            _disposedValue = true;
        }

        // Call base class implementation.
        base.Dispose(disposing);
    }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class DerivedClassWithSafeHandle : Inherits BaseClassWithSafeHandle
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False
    ' Instantiate a SafeHandle instance.
    Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

    ' Protected implementation of Dispose pattern.
    Protected Overrides Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            handle.Dispose()
            ' Free any other managed objects here.
            '
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True

        ' Call base class implementation.
        MyBase.Dispose(disposing)
    End Sub
End Class

Not

Önceki örnek, bir SafeFileHandle nesneyi göstermek için bir nesnesi kullanır; bunun yerine ondan türetilmiş herhangi bir nesne SafeHandle kullanılabilir. Örneğin nesnesinin düzgün şekilde örneklemez olduğunu unutmayın SafeFileHandle .

Geçersiz kılan türetilmiş bir sınıf için Dispose deseninin uygulanması için genel bir model aşağıda verilmiştir Object.Finalize :

class DerivedClassWithFinalizer : BaseClassWithFinalizer
{
    // To detect redundant calls
    private bool _disposedValue;

    ~DerivedClassWithFinalizer() => this.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);
    }
}
Class DerivedClassWithFinalizer : Inherits BaseClassWithFinalizer
    ' Flag: Has Dispose already been called?
    Dim disposed As Boolean = False

    ' Protected implementation of Dispose pattern.
    Protected Overrides Sub Dispose(disposing As Boolean)
        If disposed Then Return

        If disposing Then
            ' Dispose managed objects that implement IDisposable.
            ' Assign null to managed objects that consume large amounts of memory or consume scarce resources.
        End If

        ' Free any unmanaged objects here.
        '
        disposed = True

        ' Call the base class implementation.
        MyBase.Dispose(disposing)
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(False)
    End Sub
End Class

Ayrıca bkz.