Yanıtlar:
Diğerleri zaten Dispose
ve Finalize
(btw Finalize
yöntemi hala dil spesifikasyonunda bir yıkıcı olarak adlandırılır) arasındaki farkı kaplamıştır , bu yüzden sadece Finalize
yöntemin kullanışlı olduğu senaryolar hakkında biraz ekleyeceğim .
Bazı tipler, tek kullanımlık kaynakları kullanmanın kolay olduğu ve tek bir işlemle elden çıkarılacağı bir şekilde kapsamaktadır. Genel kullanım genellikle şu şekildedir: aç, oku veya yaz, kapat (At). Yapıya çok iyi uyuyor using
.
Diğerleri biraz daha zor. WaitEventHandles
örnekler için bir iş parçacığından diğerine sinyal göndermek için kullanıldığından böyle kullanılmaz. O zaman soru Dispose
bunlara kimi çağırmalı ? Bunlar gibi bir koruma türü olarak Finalize
, örnek artık uygulama tarafından başvurulmadığında kaynakların atılmasını sağlayan bir yöntem uygular .
Finalize
, bir kaynağı canlı tutmakla ilgilenen birkaç nesne olduğunda, ancak kaynağa ilgi duymayı bırakan bir nesnenin, sonuncusu. Bu durumda, Finalize
genellikle sadece kimse nesneye ilgi duymadığında ateş eder. Gevşek zamanlaması Finalize
dosyalar ve kilitler gibi mantar olmayan kaynaklar için korkunçtur, ancak mantar kaynakları için uygun olabilir.
Sonlandırıcı yöntemi, nesneniz çöp toplandığında çağrılır ve bunun ne zaman olacağının garantisi yoktur (zorlayabilirsiniz, ancak performansa zarar verir).
Dispose
Öte yandan yöntem temizlemek ve edindiğiniz tüm kaynaklarını (yönetilmeyen veri, veritabanı bağlantıları, dosya kolları, vb) kodu ile yapılır an serbest bırakabilirsiniz böylece sınıf oluşturulmuş kod tarafından çağrılacak anlamına gelir nesneniz.
Standart uygulama uygulamaktır IDisposable
ve Dispose
böylece nesnenizi bir using
ifadede kullanabilirsiniz. Gibi using(var foo = new MyObject()) { }
. Ve sonlandırıcınızda, Dispose
arama kodunun sizi atmayı unutması durumunda ararsınız.
Sonlandırma, bir nesneyi geri çağırdığında çöp toplayıcı tarafından çağrılan geri döndürmez yöntemdir. Amaç, GC'nin nesneye dönene kadar süresiz olarak bekletilmesinden ziyade artık gerekli olmadığında değerli yerel kaynakları (pencere tutamaçları, veritabanı bağlantıları, vb.) Serbest bırakmak için uygulamalar tarafından çağrılan "deterministik temizleme" yöntemidir.
Bir nesnenin kullanıcısı olarak her zaman Dispose öğesini kullanırsınız. Sonuçlandırma GC içindir.
Bir sınıfın uygulayıcısı olarak, elden çıkarılması gereken yönetilen kaynaklara sahipseniz, Dispose uygularsınız. Yerel kaynaklara sahipseniz, hem Dispose hem de Finalize yöntemlerini uygularsınız ve her ikisi de yerel kaynakları serbest bırakan ortak bir yöntem çağırır. Bu deyimler genellikle çağrıları true ile birlikte imha eden ve false ile çağrıları sonlandıran özel bir Dispose (bool çöpe) yöntemi ile birleştirilir. Bu yöntem her zaman yerel kaynakları serbest bırakır, ardından eleme parametresini denetler ve doğruysa yönetilen kaynakları atar ve GC.SuppressFinalize öğesini çağırır.
Dispose
iyi ve doğru şekilde uygulamak genellikle kolaydır. Finalize
kötüdür ve doğru şekilde uygulanması genellikle zordur. Diğer şeylerin yanı sıra, GC hiçbir nesnenin kimliğinin o nesneye herhangi bir referans olduğu sürece "geri dönüştürülmesini" sağlayamayacağından Disposable
, bazıları zaten temizlenmiş olabilecek bir grup nesneyi temizlemek kolaydır. sorun değil; Dispose
önceden çağrılmış olan bir nesneye yapılan herhangi bir başvuru , zaten çağrılmış olan bir nesneye başvuru olarak kalacaktır Dispose
.
Fred
# 42 dosya tanıtıcısına sahipse ve onu kapatırsa, sistem aynı numarayı başka bir varlığa verilen dosya tanıtıcısına ekleyebilir. Bu durumda, # 42 dosya tanıtıcısı Fred'in kapalı dosyasına değil, diğer varlık tarafından etkin olarak kullanılan dosyaya başvurur; için Fred
yakın sap # 42 denemek için tekrar felaket olur. Yönetilmeyen bir nesnenin henüz serbest bırakılıp bırakılmadığını% 100 güvenilir şekilde takip etmeye çalışılabilir. Birden fazla nesneyi takip etmeye çalışmak çok daha zordur.
Sonuçlandırmak
protected
değil, public
ya private
yöntem doğrudan uygulamanın kodundan çağrılamaz böylece aynı zamanda, bir çağrı yapabilir base.Finalize
yöntemleElden çıkarmak
IDisposable
Sonlandırıcı bulunan her tipte uygulayınDispose
Yönteme çağrı yaptıktan sonra bir nesnenin kullanılamaz hale getirildiğinden emin olun . Başka bir deyişle, Dispose
yöntem çağrıldıktan sonra bir nesneyi kullanmaktan kaçının .Dispose
tüm IDisposable
türleri arayınDispose
hataları artırmadan defalarca çağrılacak.Dispose
kullanan yöntemin GC.SuppressFinalize
yöntemiDispose
Yöntemlerin içinden istisnalar atmaktan kaçınınAtma / Sonlandırılmış Desen
Dispose
ve Finalize
yönetilmeyen kaynakları ile çalışırken. Finalize
Uygulama aday olacağını ve kaynaklar hala nesne bir geliştirici aramaya ihmal eğer çöp bile toplanan olduğunda serbest bırakılacağı Dispose
açıkça yöntemi.Finalize
Yöntemdeki yöntemlerin yanı sıra yönetilmeyen kaynakları da temizleyin Dispose
. Ayrıca, Dispose
bu sınıf içinde bileşenler olarak sahip olduğunuz herhangi bir .NET nesnesi için yöntemi (üye olarak yönetilmeyen kaynaklara sahip olan) yöntemden çağırın Dispose
.Bu nesne artık kullanılmadığında sonlandırma GC tarafından çağrılır.
Dispose, bu sınıftaki kullanıcının kaynakları serbest bırakmak için çağırabileceği normal bir yöntemdir.
Kullanıcı Dispose'i aramayı unuttuysa ve sınıfta Finalize uygulanmışsa GC çağrıldığından emin olur.
MCSD Sertifikasyon Araç Seti (sınav 70-483) sayfa 193 kitabından bazı anahtarlar var:
yıkıcı ≈ (neredeyse eşittir) base.Finalize()
, Destructor, destructor kodunu yürüten ve sonra temel sınıfın Finalize yöntemini çağıran Finalize yönteminin geçersiz kılma sürümüne dönüştürülür. O zaman ne zaman çağrılacağını bilemez tamamen deterministik olmayan çünkü GC bağlıdır.
Bir sınıf yönetilen ve yönetilmeyen kaynak içermiyorsa , onu uygulamamalı IDisposable
veya yıkıcıya sahip olmamalıdır .
Eğer sınıf sadece kaynakları yönetmişse , uygulamalı IDisposable
ama yıkıcı olmamalıdır. (Yıkıcı yürütüldüğünde, yönetilen nesnelerin hala var olduğundan emin olamazsınız, bu yüzden Dispose()
yöntemlerini yine de çağıramazsınız .)
Sınıfta yalnızca yönetilmeyen kaynaklar varsa , IDisposable
programın çağrılmaması durumunda uygulanması ve bir yıkıcıya ihtiyacı vardır Dispose()
.
Dispose()
yöntemi birden fazla çalıştırmak için güvenli olmalıdır. Daha önce çalıştırılıp çalıştırılmadığını takip etmek için bir değişken kullanarak bunu başarabilirsiniz.
Dispose()
hem yönetilen hem de yönetilmeyen kaynakları serbest bırakmalıdır .
Yıkıcı yalnızca yönetilmeyen kaynakları serbest bırakmalıdır . Yıkıcı yürütüldüğünde, yönetilen nesnelerin hala var olduğundan emin olamazsınız, bu yüzden yine de Dispose yöntemlerini çağıramazsınız. Bu, protected void Dispose(bool disposing)
sadece yönetilen kaynakların serbest bırakıldığı (atıldığı) kanonik desen kullanılarak elde edilir disposing == true
.
Kaynakları serbest bıraktıktan sonra, Dispose()
çağırmalıGC.SuppressFinalize
, böylece nesne sonlandırma sırasını atlayabilir.
Yönetilmeyen ve yönetilen kaynaklara sahip bir sınıf için uygulama örneği:
using System;
class DisposableClass : IDisposable
{
// A name to keep track of the object.
public string Name = "";
// Free managed and unmanaged resources.
public void Dispose()
{
FreeResources(true);
// We don't need the destructor because
// our resources are already freed.
GC.SuppressFinalize(this);
}
// Destructor to clean up unmanaged resources
// but not managed resources.
~DisposableClass()
{
FreeResources(false);
}
// Keep track if whether resources are already freed.
private bool ResourcesAreFreed = false;
// Free resources.
private void FreeResources(bool freeManagedResources)
{
Console.WriteLine(Name + ": FreeResources");
if (!ResourcesAreFreed)
{
// Dispose of managed resources if appropriate.
if (freeManagedResources)
{
// Dispose of managed resources here.
Console.WriteLine(Name + ": Dispose of managed resources");
}
// Dispose of unmanaged resources here.
Console.WriteLine(Name + ": Dispose of unmanaged resources");
// Remember that we have disposed of resources.
ResourcesAreFreed = true;
}
}
}
Zamanın% 99'u da endişelenmenize gerek yok. :) Ancak, nesneleriniz yönetilmeyen kaynaklara (örneğin pencere tanıtıcıları, dosya tanıtıcıları) başvuru içeriyorsa, yönetilen nesnenizin bu kaynakları serbest bırakması için bir yol sağlamanız gerekir. Sonlandırma, kaynakları serbest bırakma üzerinde örtük kontrol sağlar. Çöp toplayıcı tarafından çağrılır. Dispose, kaynakların serbest bırakılması üzerinde açık bir kontrol sağlamanın bir yoludur ve doğrudan çağrılabilir.
Çöp Toplama konusu hakkında öğrenilecek çok şey var , ama bu bir başlangıç.
Sonlandırıcı örtülü temizleme içindir - bir sınıf kesinlikle temizlenmesi gereken kaynakları yönettiğinde kullanmalısınız , aksi takdirde tutamak / bellek vb.
Bir sonlandırıcıyı doğru şekilde uygulamak çok zordur ve mümkün olduğunca kaçınılmalıdır - SafeHandle
sınıf (.Net v2.0 ve üstü için geçerlidir) artık çok nadiren (eğer varsa) artık bir sonlandırıcı uygulamanız gerektiği anlamına gelir.
IDisposable
Arayüz açık temizleme içindir ve çok daha yaygın olarak kullanılan - onlar bir nesneyi kullanmayı bitirdikten zaman kullanıcıların açıkça serbest bırakmak ya da temizleme kaynakları sağlamak için bu kullanmalısınız.
Bir sonlandırıcıya sahipseniz, IDisposable
kullanıcılara bu kaynakları toplanan nesnenin çöp toplanmış olması durumunda olduğundan daha çabuk yayınlamasına izin vermek için arayüzü de uygulamanız gerektiğini unutmayın .
Sonlandırıcılar ve konusunda en iyi ve en eksiksiz öneriler kümesi olarak düşündüğüm şeyler için DG Güncellemesi: İmha, Sonlandırma ve Kaynak Yönetimi bölümüne bakın IDisposable
.
Özet -
Ayrıca, başka bir fark - Dispose () uygulamasında, yönetilen kaynakları da serbest bırakmanız gerekirken , Finalizer'da yapılmamalıdır. Bunun nedeni, nesnenin başvurduğu yönetilen kaynakların, sonlandırılmaya hazır olmadan önce zaten temizlenmiş olmalarıdır.
Yönetilmeyen kaynakları kullanan bir sınıf için en iyi uygulama, bir geliştiricinin nesneyi açıkça atmayı unutması durumunda, hem Dispose () yöntemi hem de Finalizer - bir geri dönüş olarak kullanılacak şekilde tanımlamaktır. Her ikisi de yönetilen ve yönetilmeyen kaynakları temizlemek için paylaşılan bir yöntem kullanabilir:
class ClassWithDisposeAndFinalize : IDisposable
{
// Used to determine if Dispose() has already been called, so that the finalizer
// knows if it needs to clean up unmanaged resources.
private bool disposed = false;
public void Dispose()
{
// Call our shared helper method.
// Specifying "true" signifies that the object user triggered the cleanup.
CleanUp(true);
// Now suppress finalization to make sure that the Finalize method
// doesn't attempt to clean up unmanaged resources.
GC.SuppressFinalize(this);
}
private void CleanUp(bool disposing)
{
// Be sure we have not already been disposed!
if (!this.disposed)
{
// If disposing equals true i.e. if disposed explicitly, dispose all
// managed resources.
if (disposing)
{
// Dispose managed resources.
}
// Clean up unmanaged resources here.
}
disposed = true;
}
// the below is called the destructor or Finalizer
~ClassWithDisposeAndFinalize()
{
// Call our shared helper method.
// Specifying "false" signifies that the GC triggered the cleanup.
CleanUp(false);
}
Bildiğim en iyi örnek.
public abstract class DisposableType: IDisposable
{
bool disposed = false;
~DisposableType()
{
if (!disposed)
{
disposed = true;
Dispose(false);
}
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
}
public void Close()
{
Dispose();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// managed objects
}
// unmanaged objects and resources
}
}
C # 'da Sonlandırma ve Atma yöntemleri arasındaki fark.
GC, yönetilmeyen kaynakları (dosya işletimi, windows api, ağ bağlantısı, veritabanı bağlantısı gibi) geri almak için sonlandırma yöntemini çağırır, ancak GC bunu çağırdığında zaman sabit değildir. Buna dolaylı olarak GC denir, üzerinde düşük seviye kontrolümüz yoktur.
Atma Yöntemi: Koddan dediğimiz gibi üzerinde düşük seviye kontrolümüz var. kullanılabilir olmadığını düşündüğümüzde yönetilmeyen kaynakları geri alabiliriz.
Sınıf örnekleri genellikle çalışma zamanı tarafından yönetilmeyen kaynaklar (pencere tutamaçları (HWND), veritabanı bağlantıları vb.) Üzerindeki denetimi kapsar. Bu nedenle, bu kaynakları boşaltmak için hem açık hem de örtük bir yol sağlamalısınız. Korumalı Sonlandırma Yöntemi'ni bir nesneye (C # 'da yıkıcı sözdizimi ve C ++ için Yönetilen Uzantılar) uygulayarak örtük denetim sağlayın. Çöp toplayıcı, bu nesneye artık geçerli referanslar kalmadığında bir noktada bu yöntemi çağırır. Bazı durumlarda, bir nesne kullanan programcılara, çöp toplayıcı nesneyi serbest bırakmadan önce bu dış kaynakları açıkça serbest bırakma özelliğine sahip olmak isteyebilirsiniz. Harici bir kaynak az veya pahalıysa, programcı artık kullanılmadığında kaynakları açıkça serbest bırakırsa daha iyi performans elde edilebilir. Açık kontrol sağlamak için, IDisposable Interface tarafından sağlanan Dispose yöntemini uygulayın. Nesne tüketicisi, nesne kullanılarak yapıldığında bu yöntemi çağırmalıdır. Nesneye başka referanslar canlı olsa bile imha çağrılabilir.
Dispose yoluyla açık kontrol sağlasanız bile, Finalize yöntemini kullanarak örtük temizleme sağlamanız gerektiğini unutmayın. Sonlandırma, programcı Dispose'i çağırmazsa kaynakların kalıcı olarak sızmasını önlemek için bir yedekleme sağlar.
Dispose ve Finalize arasındaki temel fark şudur:
Dispose
genellikle kodunuz tarafından çağrılır. Kaynakları aradığınızda anında serbest bırakılır. İnsanlar yöntemi çağırmayı unuturlar, bu yüzden using() {}
ifade icat edilir. Programınız içindeki kodun yürütülmesini tamamladığında, yöntemi otomatik olarak {}
çağırır Dispose
.
Finalize
kodunuz tarafından çağrılmamış. Çöp Toplayıcı (GC) tarafından çağrılması kastedilmektedir. Bu, GC'nin buna karar verdiği her zaman kaynağın gelecekte serbest bırakılabileceği anlamına gelir. GC işini yaptığında, birçok Sonlandırma yönteminden geçecektir. Eğer bu konuda ağır bir mantığınız varsa, süreci yavaşlatacaktır. Programınız için performans sorunlarına neden olabilir. Oraya ne koyduğunuza dikkat edin.
İmha mantığının çoğunu kişisel olarak Dispose'e yazardım. Umarım, bu karışıklığı giderir.
Bildiğimiz gibi, imha etme ve sonlandırma her ikisi de yönetilmeyen kaynakları serbest bırakmak için kullanılır .. ancak fark nihai hale getirme kaynakları boşaltmak için iki döngü kullanır, burada dispose olarak bir döngü kullanır ..
İlk bölümde cevap vermek için, insanların aynı sınıf nesnesi için farklı yaklaşımlar kullandıkları örnekler vermelisiniz. Aksi takdirde cevap vermek zor (hatta garip).
İkinci soruya gelince daha iyi önce bunu okuyun ıdisposable arabiriminin uygun kullanım hangi iddialar olduğunu
Seçim senin! Ancak İmha Et'i seçin.
Başka bir deyişle: GC sadece finalizörü bilir (eğer varsa. Microsoft'un yıkıcısı olarak da bilinir). İyi bir kod her ikisinden de temizlemeye çalışır (sonlandırıcı ve Atma).