Ne zaman bir yıkıcı oluşturmalıyım?


185

Örneğin:

public class Person
{
    public Person()
    {
    }

    ~Person()
    {
    }
}

Ne zaman el ile bir yıkıcı oluşturmalıyım? Bir yıkıcı yaratmak için ne zaman ihtiyacın vardı?


1
C # dili bu "yıkıcıları" olarak adlandırır, ancak çoğu kişi onlara "finalizörler" adını verir, çünkü bu .NET adlarıdır ve C ++ yıkıcılarıyla (oldukça farklı olan) karışıklığı azaltır. Tek Kullanımlık ve Sonlandırıcılar Nasıl Uygulanır: 3 Kolay Kural
Stephen Cleary

5
Dikkatsiz hissettiğin zaman.
capdragon

32
TomTom'un klavyesi arızalı olduğunu düşünüyorum. Büyük harf kilidi ara sıra açılıp kapanıyordu. Tuhaf.
Jeff LaFay


Greg Beech'in önerisine dayalı bir hata ayıklayıcı yardımcısı olarak bir yıkıcı kullandım: stackoverflow.com/questions/3832911/…
Brian

Yanıtlar:


237

GÜNCELLEME: Bu soru Mayıs 2015'teki blogumun konusuydu . Bu mükemmel soru için teşekkürler! İnsanların kesinleştirme konusunda yaygın olarak inandıkları uzun bir yanlışlık listesi için bloga bakın.

Ne zaman el ile bir yıkıcı oluşturmalıyım?

Neredeyse hiç.

Tipik olarak bir kişi sadece sınıfınız nesne kaybolduğunda temizlenmesi gereken bazı pahalı yönetilmeyen kaynaklara tutunursa bir yıkıcı oluşturur. Kaynağın temizlendiğinden emin olmak için tek kullanımlık desen kullanmak daha iyidir. Bir yıkıcı, esasen, nesnenizin tüketicisi onu atmayı unutursa, kaynağın yine de temizlendiğinin bir güvencesidir. (Olabilir.)

Bir yıkıcı yaparsanız son derece dikkatli olun ve çöp toplayıcının nasıl çalıştığını anlayın . Yıkıcılar gerçekten garip :

  • Onlar senin iş parçacığında çalışmaz; kendi başlıkları üzerinde çalışırlar. Kilitlenmelere neden olma!
  • Bir yıkıcıdan atılan işlenmemiş bir istisna kötü bir haberdir. Kendi iş parçacığında; onu kim yakalayacak?
  • Bir yıkıcı , kurucu başladıktan sonra ancak kurucu bitmeden önce bir nesneye çağrılabilir . Düzgün yazılmış bir yıkıcı, kurucuda kurulan değişmezlere güvenmeyecektir.
  • Bir yıkıcı bir nesneyi "diriltebilir" ve ölü bir nesneyi tekrar canlandırabilir. Bu gerçekten garip. Yapma.
  • Bir yıkıcı asla kaçamaz; kesinleştirme için planlanan nesneye güvenemezsiniz. Bu muhtemelen olacak, ama bu bir garanti değil.

Bir yıkıcıda normalde doğru olan neredeyse hiçbir şey doğru değildir. Gerçekten, gerçekten dikkatli olun. Doğru bir yıkıcı yazmak çok zordur.

Bir yıkıcı yaratmak için ne zaman ihtiyacın vardı?

Derleyicinin yıkıcıları işleyen kısmını test ederken. Üretim kodunda bunu hiç yapmam gerekmedi. Nadiren yönetilmeyen kaynakları işleyen nesneler yazıyorum.


"Bir yıkıcı, kurucu başladıktan sonra ancak kurucu bitmeden önce bir nesneye çağrılabilir." Ama alan başlatıcılarının çalışmasına güvenebilirim, değil mi?
yapılandırıcı

13
@configurator: Hayır. Bir nesnenin üçüncü alan başlatıcısının, bir istisnanın atılmasına neden olan statik yöntem adı verilen bir sonlandırıcıya sahip olduğunu varsayalım. Dördüncü alan başlatıcısı ne zaman çalışır? Asla. Ancak nesne hala tahsis edilmiştir ve sonuçlandırılmalıdır. Heck, dtor çalıştığında double türündeki alanların tamamen başlatıldığına dair bir garantiniz bile yok . Çifte yazı yazmanın yarısında ip ipliği kesilmiş olabilir ve şimdi sonlandırıcı yarı başlangıçlı yarı sıfır çift ile uğraşmak zorundadır.
Eric Lippert

1
Mükemmel yazı, ama "sınıf bazı pahalı yönetilmeyen nesnenin üzerinde tutarak veya çok sayıda yönetilmeyen nesnelerin var olmasına neden olduğunda oluşturulmalıdır" demeliydim - Somut bir örnek için, temel bir yerel C ++ kullanan C # bir matris sınıf var çok ağır kaldırma yapmak için matris sınıfı - Çok fazla matris yapıyorum - bir "yıkıcı" bu özel durumda düşünülemez çok daha üstündür, çünkü evin yönetilen ve yönetilmeyen taraflarını daha iyi senkronize tutar
Mark Mullin

1
pythonnet yönetilmeyen CPython GIL serbest bırakmak için yıkıcı kullanır
denfromufa

3
Harika makale Eric. Bunun için aksesuarlar -> "Ekstra bonus eğlence: çalışma zamanı, hata ayıklayıcıda programı çalıştırırken daha az agresif kod üretimi ve daha az agresif çöp toplama kullanır, çünkü hata ayıkladığınız nesnelerin aniden kaybolmasına rağmen kötü bir hata ayıklama deneyimidir. nesneye atıfta bulunan değişken kapsam dahilindedir. Bu, bir nesnenin çok erken sonlandırıldığı bir hatanız varsa, muhtemelen bu hatayı hata ayıklayıcıda yeniden oluşturamayacağınız anlamına gelir! "
Ken Palmer

17

Buna "sonlandırıcı" denir ve genellikle durumu (yani: alanları) yönetilmeyen kaynakları içeren bir sınıf için yalnızca bir tane oluşturmalısınız (yani: p / invoke çağrıları yoluyla alınan tutamaçlara işaretçiler). Ancak, .NET 2.0 ve sonraki sürümlerde, yönetilmeyen kaynakların temizlenmesi ile ilgilenmenin daha iyi bir yolu vardır: SafeHandle . Bu göz önüne alındığında, bir daha asla finalizer yazmanıza gerek yoktur.


25
@ThomasEding - Evet öyle . C #, yıkıcı sözdizimini kullanır, ancak aslında bir sonlandırıcı oluşturur . Tekrar .
JDB hala

@JDB: Dilsel yapıya yıkıcı denir. Adı beğenmedim, ama buna denir. Bir yıkıcı bildirme eylemi, derleyicinin yıkıcı gövdesinde görünenlerle birlikte biraz sarıcı kod içeren bir sonlandırıcı yöntemi üretmesine neden olur.
supercat

8

Sınıfınız Windows dosya tanıtıcıları gibi yönetilmeyen kaynakları tutmadıkça bunlara ihtiyacınız yoktur.


5
Aslında, buna yıkıcı denir
David Heffernan

2
Şimdi kafam karıştı. Sonlandırıcı mı yoksa yıkıcı mı?

4
C # spec aslında bir yıkıcı diyor. Bazıları bunu bir hata olarak görür. stackoverflow.com/questions/1872700/…
Ani

2
@ThomasEding - Evet öyle . C #, yıkıcı sözdizimini kullanır, ancak aslında bir sonlandırıcı oluşturur .
JDB hala

2
Buradaki yorumları seviyorum, gerçek panto :)
Benjol

4

Buna yıkıcı / sonlandırıcı denir ve genellikle Atılan kalıbı uygularken oluşturulur.

Sınıfınızın kullanıcısı (sonunda) kaynaklarınızın serbest bırakıldığından emin olmak için Dispose'i aramayı unuttuğunda, ancak yıkıcının ne zaman çağrıldığına dair herhangi bir garantiniz olmadığında geri dönüşlü bir çözümdür.

Bu Yığın Taşması sorusunda , kabul edilen yanıt, imha modelinin nasıl uygulanacağını doğru şekilde gösterir. Bu, yalnızca sınıfınızda çöp toplayıcının kendini temizlemeyi başaramadığı el değmemiş kaynaklar varsa gereklidir.

İyi bir uygulama da, sınıf kullanıcısına kaynakları hemen boşaltmak için nesneyi manuel olarak elden çıkarma imkanı vermeden bir sonlandırıcı uygulamak değildir.


Aslında iyi bir sebeple C # 'da yıkıcı olarak adlandırılmaz.
TomTom

14
Aslında öyle . Bana bir aşağılık oy verdiğiniz için teşekkürler çünkü yanılıyorsunuz. Bu özel sorunla ilgili MSDN kitaplığına bakın
Øyvind Bråthen

1
@TomTom resmi adı yıkıcı
David Heffernan

Aslında bir geri dönüş yöntemi değil, sadece nesneleriniz yönetilmeyen kaynakları serbest bıraktığında GC'nin yönetmesine izin verir, IDisposable'ı uygulamak bunu kendiniz yönetmenize izin verir.
HasaniH

3

Yönetilmeyen kaynaklarınız olduğunda ve nesneniz kaybolduğunda bunların temizleneceğinden emin olmanız gerektiğinde. İyi örnek COM nesneleri veya Dosya İşleyicileri olabilir.


2

Bir nesnenin bir WPF uygulaması kapsamında bellekten temizlendiğini görmek için bir yıkıcı (yalnızca hata ayıklama amacıyla) kullandım. Çöp toplamanın nesneyi bellekten gerçekten temizleyip temizlemediğinden emin değildim ve bu doğrulamanın iyi bir yoluydu.


1

Yıkıcılar, sınıfınızda kapsüllenmiş yönetilmeyen kaynakları boşaltmanın örtük bir yolunu sağlarlar, GC ona ulaştığında çağrılır ve dolaylı olarak temel sınıfın Sonlandırma yöntemini çağırırlar. Yönetilmeyen çok fazla kaynak kullanıyorsanız, IDisposable arabirimi aracılığıyla bu kaynakları boşaltmanın açık bir yolunu sunmak daha iyidir. C # programlama kılavuzuna bakın: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.