Aracılığıyla paylaş


Dispose metodu uygulama

Dispose yöntemi öncelikle yönetilmeyen kaynakları serbest bırakmak için uygulanır. Uygulama olan IDisposable örnek üyeleriyle çalışırken çağrıları art arda Dispose çağırmak yaygın bir durum olur. uygulamasının Disposebaş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ısı yönetilmeyen bellek ayırmaz veya serbest bırakmaz. Atma deseni olarak adlandırılan bir nesneyi atmak için desen, bir nesnenin yaşam süresine göre sıra uygular. Dispose deseni, arabirimini uygulayan IDisposable 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öntemin bir özel durum oluşturmadan birden çok kez çağrılabilecek şekilde bir kez etkili olması gerekir. Ayrıca, sonraki çağrıları Dispose hiçbir şey yapmaz.

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

İpucu

Bağımlılık ekleme ile ilgili olarak, hizmetleri bir IServiceCollection'a kaydederken hizmet ömrü sizin adınıza örtük olarak yönetilir. IServiceProvider ve karşılık gelen IHost kaynak temizlemeyi düzenler. Özel olarak, ve IAsyncDisposable uygulamaları IDisposable belirtilen yaşam süresi sonunda düzgün bir şekilde atılır.

Daha fazla bilgi için bkz . .NET'te 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, sonlandırıcı uygulamak yerine nesneleri oluşturmanızı System.Runtime.InteropServices.SafeHandle öneririz.

A System.Runtime.InteropServices.SafeHandle , yönetilmeyen bir kaynağı tanımlayan bir System.IntPtr öğesini sarmalayan 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 kaynağın atıldığında SafeHandle veya tüm başvuruları bırakıldığında ve örneğin son haline getirildiğinde bu kaynağın bir kez ve yalnızca bir kez yayınlandığından SafeHandleSafeHandle 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ı 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 olarak kabul edildiğini ve tanıtıcının nasıl serbest edileceğini doğrular. Örneğin, SafeFileHandle öğesinden SafeHandle türetilir ve IntPtrs açık dosya tanıtıcılarını/tanımlayıcılarını SafeHandle.ReleaseHandle() tanımlar ve kapatmak için yöntemini geçersiz kılar (Unix'te işlevi veya CloseHandle Windows'da işlev aracılığıylaclose). Yönetilmeyen kaynak oluşturan .NET kitaplıklarındaki çoğu API, ham işaretçiyi geri vermek yerine bunu bir SafeHandle içine sarmalar ve gerektiğinde size döndürür SafeHandle . Yönetilmeyen bir bileşenle etkileşime geçtiğinizde ve yönetilmeyen bir kaynak için bir aldığınızda IntPtr , sarmalamak için kendi SafeHandle türünüzü oluşturabilirsiniz. Sonuç olarak, birkaç türü olmayanSafeHandle sonlandırıcıları uygulamak gerekir. Atılabilir desen uygulamalarının çoğu yalnızca diğer yönetilen kaynakları sarmalar ve bazıları nesne olabilir SafeHandle .

Ad alanında Microsoft.Win32.SafeHandles 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ı

Dispose() ve Dispose(bool)

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

Yöntem imzaları şunlardır:

  • public sanal olmayan (NotOverridable Visual Basic'te) (IDisposable.Dispose uygulama).
  • protected virtual (Overridable Visual Basic'te) Dispose(bool).

Dispose() yöntemi

publicsanal olmayan (NotOverridable Visual Basic'te) parametresiz Dispose yöntem artık gerekli olmadığında (türün tüketicisi tarafından) çağrıldığından, amacı yönetilmeyen kaynakları serbest bırakın, genel temizleme gerçekleştirin ve varsa sonlandırıcının çalışması gerekmediğini belirtmektir. Yönetilen nesneyle ilişkili gerçek belleği boşaltmak her zaman çöp toplayıcının 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, yöntemine SuppressFinalize 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 çağrısının GC.SuppressFinalize hiçbir etkisi olmaz. Gerçek temizleme yöntemi aşırı yüklemesi tarafından Dispose(bool) gerçekleştirilir.

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

Aşırı yüklemede disposing parametresiBoolean, yöntem çağrısının bir yöntemden mi (değeri) trueyoksa sonlandırıcıdan Dispose mı geldiğini (değeri olur) gösteren bir parametredirfalse.

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

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

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

  • Nesne zaten atılmışsa koşullu dönüş için bir blok.

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

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

    • uygulayan IDisposableyönetilen nesneler. Koşullu blok, uygulamalarını Dispose çağırmak için kullanılabilir (art arda atma). Yönetilmeyen kaynağınızı sarmak için türetilmiş sınıfını System.Runtime.InteropServices.SafeHandle kullandıysanız, uygulamayı burada çağırmalısınız SafeHandle.Dispose() .

    • Büyük miktarda bellek kullanan veya az miktarda kaynak tüketen yönetilen nesneler. Ulaşılma olasılığını daha yüksek hale getirmek için büyük yönetilen nesne başvuruları null atayın. Bu, onları belirsiz bir şekilde geri kazanılmalarından daha hızlı serbest bırakı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 atılmış olabilecek yönetilen nesnelerle etkileşim kurmadığından 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.

Çağrıları art arda at

Sınıfınız bir alana veya özelliğe sahipse ve türü uyguluyorsa IDisposable, içeren sınıfın da uygulaması IDisposablegerekir. Bir uygulamanın örneğini IDisposable oluşturan ve örnek üyesi olarak depolayan bir sınıf da temizlemeden sorumludur. Bu, başvuruda bulunu atılabilir türlerin yöntemi aracılığıyla temizleme işlemini belirleme fırsatı verilmesine Dispose yardımcı olur. Aşağıdaki örnekte sınıfıdır sealed (veya NotInheritable Visual Basic'te).

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

İpucu

  • Sınıfınızın bir IDisposable alanı veya özelliği varsa ancak buna sahip değilse, yani sınıfın nesnesini oluşturmadığı anlamına gelir ve sınıfın uygulaması IDisposablegerekmez.
  • Sonlandırıcıda -checking gerçekleştirmek nullisteyebileceğiniz durumlar vardır (sonlandırıcı tarafından çağrılan yöntemi içerir Dispose(false) ). Bunun birincil nedenlerinden biri, örneğin tam olarak başlatılıp başlatılmadığına emin olmanızdır (örneğin, bir oluşturucuda bir özel durum oluşturulabilir).

Dispose desenini uygulama

Tüm korumalı olmayan sınıflar (veya Olarak değiştirilmeyen Visual Basic sınıfları) devralınabilecekleri için olası bir temel sınıf olarak NotInheritablekabul edilmelidir. Olası herhangi bir temel sınıf için dispose desenini uygularsanız aşağıdakileri sağlamanız gerekir:

  • Dispose yöntemini çağıran Dispose(bool) bir uygulama.
  • Dispose(bool) Gerçek temizlemeyi gerçekleştiren bir yöntem.
  • Yönetilmeyen kaynağınızı sarmalayan bir sınıf SafeHandle (önerilir) veya yöntemine Object.Finalize bir geçersiz kılma. sınıfı SafeHandle bir sonlandırıcı sağlar, bu nedenle kendiniz yazmanız gerekmez.

Önemli

Temel sınıfın yalnızca yönetilen nesnelere başvurması ve dispose desenini uygulaması mümkündür. Bu gibi durumlarda, sonlandırıcı gereksizdir. Sonlandırıcı yalnızca yönetilmeyen kaynaklara doğrudan başvuruyorsanız gereklidir.

Burada, güvenli tanıtıcı kullanan bir temel sınıf için dispose deseninin uygulanmasına yönelik genel bir örnek verilmiştir.

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

Not

Önceki örnekte deseni göstermek için bir nesne kullanılır; bunun yerine öğesinden SafeHandle türetilen herhangi bir SafeFileHandle nesne kullanılabilir. Örneğin nesnesini düzgün bir şekilde örneklemediğini SafeFileHandle unutmayın.

Geçersiz kılan bir temel sınıf için dispose desenini uygulamaya yönelik genel desen aşağıdadır 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

İpucu

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

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

arabirimini uygulayan bir sınıftan IDisposable türetilen bir sınıf, IDisposabletemel sınıf uygulaması IDisposable.Dispose türetilmiş sınıfları tarafından devralındığından uygulamasını uygulamamalı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 temizlemesini gerçekleştiren bir yöntem. Bu yöntem ayrıca base.Dispose(bool) (MyBase.Dispose(bool) Visual Basic'te) yöntemini çağırarak bunu bir bağımsız değişken olarak yok etme durumunu (bool disposing parametre) geçirmelidir.
  • Yönetilmeyen kaynağınızı sarmalayan bir sınıf SafeHandle (önerilir) veya yöntemine Object.Finalize bir geçersiz kılma. sınıfı, SafeHandle sizi bir koda gerek kalmadan kurtaran bir sonlandırıcı sağlar. Bir sonlandırıcı sağlarsanız, bağımsız değişkenle false aşırı yüklemeyi çağırması Dispose(bool) 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 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

Not

Önceki örnekte deseni göstermek için bir nesne kullanılır; bunun yerine öğesinden SafeHandle türetilen herhangi bir SafeFileHandle nesne kullanılabilir. Örneğin nesnesini düzgün bir şekilde örneklemediğini SafeFileHandle unutmayın.

Geçersiz kılan türetilmiş bir sınıf için dispose desenini uygulamaya yönelik genel desen aşağıdadır 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

Ayrıca bkz.