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 SafeHandle
SafeHandle
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
public
sanal 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) true
yoksa 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
isetrue
bu 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
null
isteyebileceğiniz durumlar vardır (sonlandırıcı tarafından çağrılan yöntemi içerirDispose(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 NotInheritable
kabul 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ıcabase.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