Dalam C # apa perbedaan antara destruktor dan metode Finalisasi di kelas?

97

Apa perbedaan, jika ada, antara destruktor dan metode Finalisasi di kelas?

Saya baru-baru ini menemukan bahwa Visual Studio 2008 menganggap destruktor identik dengan metode Finalize, yang berarti bahwa Visual Studio tidak akan membiarkan Anda secara bersamaan menentukan kedua metode di kelas.

Misalnya, fragmen kode berikut:

class TestFinalize
{
    ~TestFinalize()
    {
        Finalize();
    }

    public bool Finalize()
    {
        return true;
    }
}

Memberikan kesalahan berikut pada panggilan untuk Menyelesaikan di destruktor:

Panggilan tersebut ambigu antara metode atau properti berikut: 'TestFinalize. ~ TestFinalize ()' dan 'TestFinalize.Finalize ()'

Dan jika panggilan ke Finalize dikomentari, itu memberikan kesalahan berikut:

Ketik 'ManagementConcepts.Service.TestFinalize' sudah mendefinisikan anggota bernama 'Finalize' dengan jenis parameter yang sama

Jeff Leonard
sumber

Jawaban:

68

Penghancur dalam System.Object.Finalizemetode C # menimpa . Anda harus menggunakan sintaks destruktor untuk melakukannya. Mengganti secara manual Finalizeakan memberi Anda pesan kesalahan.

Pada dasarnya apa yang Anda coba lakukan dengan Finalizedeklarasi metode Anda menyembunyikan metode kelas dasar. Ini akan menyebabkan kompiler mengeluarkan peringatan yang bisa dibungkam menggunakan newpengubah (jika itu akan berhasil). Hal penting yang perlu diperhatikan di sini adalah bahwa Anda tidak dapat sekaligus overridemendeklarasikan newanggota dengan nama yang identik pada saat yang sama sehingga memiliki destruktor dan Finalizemetode akan menghasilkan kesalahan (tetapi Anda dapat , meskipun tidak disarankan, mendeklarasikan public new void Finalize()metode jika Anda tidak mendeklarasikan destruktor).

Mehrdad Afshari
sumber
71

Wikipedia memiliki beberapa diskusi yang bagus tentang perbedaan antara finalizer dan destruktor dalam artikel finalizer .

C # benar-benar tidak memiliki destruktor yang "benar". Sintaksnya menyerupai destruktor C ++, tetapi sebenarnya ini adalah finalizer. Anda menulisnya dengan benar di bagian pertama contoh Anda:

~ClassName() { }

Di atas adalah gula sintaksis untuk suatu Finalizefungsi. Ini memastikan bahwa finalisator di pangkalan dijamin untuk berjalan, tetapi sebaliknya identik dengan mengganti Finalizefungsi. Ini berarti bahwa saat Anda menulis sintaks destruktor, Anda benar-benar menulis finalizer.

Menurut Microsoft , finalizer mengacu pada fungsi yang dipanggil oleh pengumpul sampah saat ia mengumpulkan ( Finalize), sedangkan destruktor adalah bit kode Anda yang dijalankan sebagai hasilnya (gula sintaksis yang menjadi Finalize). Mereka sangat dekat untuk menjadi hal yang sama sehingga Microsoft seharusnya tidak pernah membuat perbedaan.

Penggunaan istilah "destruktor" C ++ oleh Microsoft menyesatkan, karena di C ++ ia dijalankan pada utas yang sama segera setelah objek dihapus atau dikeluarkan dari tumpukan, sementara di C # dijalankan pada utas terpisah di lain waktu.

Kenzi
sumber
Saya berpendapat bahwa perbedaan antara destruktor dan finalizer adalah hal yang penting untuk dibuat. Namun, hanya mereka yang peduli tentang apa yang terjadi di bawah tenda yang akan peduli dengan perbedaan tersebut.
Kyle Baran
1
Juga perhatikan ECMA-334 secara eksplisit telah menghilangkan ambiguitas "destruktor" dan "finalizer" secara formal, dahulu kala. Saya tidak tahu mengapa MS masih bersikeras menggunakan istilah yang menyesatkan dalam spesifikasinya.
FrankHB
Setidaknya dari bekerja dengan Mono, C # sebenarnya dimodelkan setelah C ++, dan sebagian besar objek C # asli adalah objek C ++. Cara kompiler yang mengompilasi Mono bekerja menentukan bagaimana objek C ++ tersebut dihancurkan, dan juga, bagaimana penyelesaian objek C # menyebar ke C ++ dan memanggil destruktor tersebut. Perbedaannya masuk akal di bawah kap, tetapi masih tidak berlaku untuk C # itu sendiri.
Kenzi
20

Ditemukan di sini: http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

  1. Penghancur

    Mereka adalah metode khusus yang berisi kode pembersihan untuk objek. Anda tidak dapat memanggilnya secara eksplisit dalam kode Anda karena mereka dipanggil secara implisit oleh GC. Di C # mereka memiliki nama yang sama dengan nama kelas yang diawali dengan ~tanda. Suka-

    Class MyClass
    {
    
    ~MyClass()
    {
    .....
    }
    }

    Di VB.NET, destruktor diimplementasikan dengan menimpa metode Finalize dari kelas System.Object.

  2. Membuang

    Ini sama seperti metode lain di kelas dan dapat dipanggil secara eksplisit tetapi mereka memiliki tujuan khusus untuk membersihkan objek. Dalam metode buang kami menulis kode pembersihan untuk objek. Penting bagi kita untuk membebaskan semua sumber yang tidak terkelola dalam metode pembuangan seperti koneksi database, file, dll. Kelas yang mengimplementasikan metode pembuangan harus mengimplementasikan antarmuka IDisposable. Metode pembuangan harus memanggil metode GC.SuppressFinalize untuk objek yang dibuang jika class memiliki desturctor karena telah melakukan pekerjaan untuk membersihkan objek, maka pengumpul sampah tidak perlu memanggil metode Finalisasi objek. Referensi: http://msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

  3. Menyelesaikan

    Metode Finalize bertindak sebagai pengaman untuk membersihkan sumber daya jika metode Buang Anda tidak dipanggil. Anda sebaiknya hanya menerapkan metode Finalize untuk membersihkan resource yang tidak terkelola. Anda tidak boleh menerapkan metode Finalize untuk objek terkelola, karena pengumpul sampah membersihkan sumber daya terkelola secara otomatis. Metode finalisasi dipanggil oleh GC secara implisit sehingga Anda tidak dapat memanggilnya dari kode Anda.

    Catatan: Di C #, metode Finalize tidak dapat ditimpa, jadi Anda harus menggunakan destruktor yang implementasi internalnya akan menimpa metode Finalize di MSIL. Tetapi di VB.NET, metode Finalize dapat ditimpa karena metode ini mendukung metode destruktor.

Pembaruan: Utas semi-terkait yang menarik di sini .

Andrew Siemer
sumber
1
You should only implement a Finalize method to clean up unmanaged resources: Anda meletakkannya di Selesaikan. Sama dengan Buang?
HQt
@hqt: Kasus di mana seseorang harus mengimplementasikan Disposejauh melebihi jumlah di mana ia harus mengimplementasikan finalizer. Implementasikan Disposejika kemungkinan instance kelas atau kelas turunan akan menjadi hal terakhir yang memiliki sumber daya yang tidak dikelola secara langsung, atau secara langsung memiliki hal terakhir untuk memiliki sumber daya yang tidak dikelola secara langsung, atau secara langsung memiliki hal terakhir untuk dimiliki secara langsung dll. Hanya terapkan Finalizeuntuk pembersihan sumber daya jika kelas seseorang <i> secara langsung </i> memiliki sumber daya yang tidak terkelola <i> dan hampir tidak ada yang lain </i> - skenario yang jauh lebih sempit.
supercat
@hqt: Jika salah satu kelas akan secara langsung memiliki sumber daya yang tidak dikelola dan juga menyimpan referensi ke objek lain, sumber daya yang tidak dikelola umumnya harus dipisahkan menjadi kelas finalnya sendiri (yang idealnya tidak memiliki referensi yang kuat ke hal lain), yang berarti kelas yang menyimpan referensi ke objek lain hanya akan memiliki "hal-hal yang secara langsung memiliki sumber daya yang tidak terkelola", daripada memiliki sumber daya itu sendiri, dan karenanya tidak memerlukan penyelesaian.
supercat