Saya sedang meninjau beberapa kode untuk seorang teman dan mengatakan bahwa dia menggunakan pernyataan pengembalian di dalam blok coba-akhirnya. Apakah kode di bagian Akhirnya masih menyala meskipun sisa blok percobaan tidak?
Contoh:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
sumber
sumber
StackOverflowException
,ExecutionEngineException
adalah beberapa dari mereka. Dan karena mereka tidak dapat ditangani,finally
tidak akan berjalan.try
blok. Tidak ada yang tentang aborsi program yang tiba-tiba.try
blok adalahreturn
pernyataan. (Pernyataan kedua dari blok itu tidak dapat dijangkau dan akan menghasilkan peringatan.)Jawaban:
Jawaban sederhana: Ya.
sumber
finally
blok akan dieksekusi.Biasanya ya. Bagian terakhir dijamin untuk mengeksekusi apa pun yang terjadi termasuk pengecualian atau pernyataan pengembalian. Pengecualian untuk aturan ini adalah pengecualian asinkron yang terjadi pada utas (
OutOfMemoryException
,StackOverflowException
).Untuk mempelajari lebih lanjut tentang pengecualian async dan kode yang dapat diandalkan dalam situasi itu, baca tentang wilayah eksekusi terbatas .
sumber
Inilah sedikit tes:
Hasilnya adalah:
sumber
WriteLine
untuk hasil dari pemanggilan metode benar-benar dilakukan. Dalam hal inireturn
panggilan menetapkan hasil metode, akhirnya menulis ke konsol - sebelum metode keluar. KemudianWriteLine
dalam metode Utama memuntahkan teks dari panggilan kembali.Mengutip dari MSDN
sumber
finally
pada kenyataannya tidak ada jaminan bahkan untuk program yang sangat biasa (yang kebetulan membuang pengecualian ini).Umumnya ya, akhirnya akan berjalan.
Untuk tiga skenario berikut, akhirnya akan SELALU berjalan:
Ini termasuk pengecualian yang sesuai dengan CLS yang berasal dari System.Exception dan pengecualian yang tidak sesuai dengan CLS, yang tidak berasal dari System.Exception. Pengecualian yang tidak memenuhi CLS secara otomatis dibungkus oleh RuntimeWrappedException. C # tidak bisa melempar pengecualian keluhan non-CLS, tetapi bahasa seperti C ++ bisa. C # dapat memanggil kode yang ditulis dalam bahasa yang dapat membuang pengecualian yang tidak sesuai dengan CLS.
Pada. NET 2.0, sebuah ThreadAbortException tidak lagi mencegah akhirnya menjalankan. ThreadAbortException sekarang diangkat ke sebelum atau sesudah akhirnya. Akhirnya akan selalu berjalan dan tidak akan terganggu oleh utas yang dibatalkan, selama upaya tersebut benar-benar dimasukkan sebelum utas yang dibatalkan terjadi.
Skenario berikut, akhirnya tidak akan berjalan:
StackOverflowException Asynchronous.
Pada. NET 2.0 stack overflow akan menyebabkan proses berakhir. Akhirnya tidak akan dijalankan, kecuali kendala lebih lanjut diterapkan untuk membuat akhirnya CER (Constrained Execution Region). CER tidak boleh digunakan dalam kode pengguna umum. Mereka hanya boleh digunakan di mana sangat penting bahwa kode pembersihan selalu dijalankan - setelah semua proses ditutup pada stack overflow dan semua objek yang dikelola karenanya akan dibersihkan secara default. Dengan demikian, satu-satunya tempat CER harus relevan adalah untuk sumber daya yang dialokasikan di luar proses, misalnya, pegangan yang tidak dikelola.
Biasanya, kode yang tidak dikelola dibungkus oleh beberapa kelas terkelola sebelum dikonsumsi oleh kode pengguna. Kelas pembungkus yang dikelola biasanya akan menggunakan SafeHandle untuk membungkus pegangan yang tidak dikelola. SafeHandle mengimplementasikan finalizer kritis, dan metode Release yang dijalankan dalam CER untuk menjamin eksekusi kode pembersihan. Untuk alasan ini, Anda seharusnya tidak melihat CER berserakan melalui kode pengguna.
Jadi fakta bahwa akhirnya tidak berjalan di StackOverflowException seharusnya tidak berpengaruh pada kode pengguna, karena prosesnya akan tetap berakhir. Jika Anda memiliki beberapa kasus tepi di mana Anda perlu membersihkan beberapa sumber daya yang tidak dikelola, di luar SafeHandle atau CriticalFinalizerObject, kemudian gunakan CER sebagai berikut; tetapi harap dicatat, ini adalah praktik yang buruk - konsep yang tidak dikelola harus diabstraksi menjadi kelas yang dikelola dan desain SafeHandle yang sesuai.
misalnya,
sumber
FailFast
internal. Satu-satunya cara saya berhasil menangkapnya adalah dengan menyesuaikan hosting runtime CLR . Perhatikan bahwa poin Anda masih valid untuk beberapa pengecualian asinkron lainnya.Ada pengecualian yang sangat penting untuk ini yang belum saya lihat disebutkan dalam jawaban lain, dan yang (setelah pemrograman dalam C # selama 18 tahun) saya tidak percaya saya tidak tahu.
Jika Anda melempar atau memicu pengecualian apa pun di dalam
catch
blok Anda (bukan hanya anehStackOverflowExceptions
dan sejenisnya), dan Anda tidak memiliki seluruhtry/catch/finally
blok di dalamtry/catch
blok lain ,finally
blok Anda tidak akan dieksekusi. Ini mudah ditunjukkan - dan jika saya tidak melihatnya sendiri, mengingat seberapa sering saya membaca bahwa itu hanya benar-benar aneh, kasus sudut kecil yang dapat menyebabkanfinally
blok tidak dieksekusi, saya tidak akan percaya.Saya yakin ada alasan untuk ini, tetapi aneh bahwa itu tidak diketahui secara luas. (Dicatat di sini misalnya, tetapi tidak di mana pun dalam pertanyaan khusus ini.)
sumber
finally
bloknya bukan untuk menangkapcatch
blok.Saya menyadari bahwa saya terlambat ke pesta tetapi dalam skenario (berbeda dari contoh OP) di mana memang ada pengecualian MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): "Jika pengecualian tidak ditangkap, eksekusi blok akhirnya tergantung pada apakah sistem operasi memilih untuk memicu operasi pelepasan pengecualian."
Blok akhirnya hanya dijamin untuk dieksekusi jika beberapa fungsi lain (seperti Main) lebih jauh dari tumpukan panggilan menangkap pengecualian. Detail ini biasanya bukan masalah karena semua lingkungan waktu berjalan (CLR dan OS) program C # berjalan pada sebagian besar sumber daya gratis yang dimiliki proses ketika keluar (menangani file dll.). Dalam beberapa kasus mungkin sangat penting: Operasi basis data setengah berjalan yang ingin Anda lakukan resp. beristirahat; atau koneksi jarak jauh yang mungkin tidak ditutup secara otomatis oleh OS dan kemudian memblokir server.
sumber
Iya. Itu sebenarnya poin utama dari pernyataan terakhir. Kecuali jika sesuatu yang katestropik terjadi (kehabisan memori, komputer dicabut, dll.) Pernyataan terakhir harus selalu dijalankan.
sumber
finally
blok jika pengecualian itu tidak pernah tertangkap. Itu mengejutkan saya ;-).Itu juga tidak akan menyala pada pengecualian tanpa penangkapan dan berjalan di utas yang di-host di Layanan Windows
Akhirnya tidak dieksekusi ketika di Thread menjalankan di Layanan Windows
sumber
akhirnya tidak akan berjalan jika Anda keluar dari aplikasi menggunakan System.exit (0); seperti dalam
hasilnya hanya: coba
sumber
c#
, tetapi sepertinya iniJava
. Dan di samping itu, dalam banyak kasusSystem.exit()
adalah petunjuk dari desain yang buruk :-)99% dari skenario akan dijamin bahwa kode di dalam
finally
blok akan berjalan, namun pikirkan skenario ini: Anda memiliki utas yang memilikitry
->finally
blok (tidakcatch
) dan Anda mendapatkan pengecualian yang tidak tertangani dalam utas itu. Dalam hal ini, utas akan keluar danfinally
bloknya tidak akan dieksekusi (aplikasi dapat terus berjalan dalam kasus ini)Skenario ini cukup langka, tetapi hanya untuk menunjukkan bahwa jawabannya tidak SELALU "Ya", itu sebagian besar waktu "Ya" dan kadang-kadang, dalam kondisi langka, "Tidak".
sumber
Tujuan utama dari blok akhirnya adalah untuk mengeksekusi apa pun yang tertulis di dalamnya. Seharusnya tidak tergantung pada apa pun yang terjadi dalam mencoba atau menangkap. Namun dengan System.Environment.Exit (1) aplikasi akan keluar tanpa pindah ke baris kode berikutnya.
sumber