Kode ini adalah bagian dari aplikasi yang membaca dari dan menulis ke database yang terhubung dengan ODBC. Ini membuat rekaman dalam database dan kemudian memeriksa apakah rekaman telah berhasil dibuat, kemudian kembali true
.
Pemahaman saya tentang aliran kendali adalah sebagai berikut:
command.ExecuteNonQuery()
didokumentasikan untuk memunculkan InvalidOperationException
ketika "panggilan metode tidak valid untuk status objek saat ini". Oleh karena itu, jika itu terjadi, eksekusi try
blok akan berhenti, finally
blok akan dieksekusi, kemudian akan dieksekusi return false;
di bagian bawah.
Namun, IDE saya mengklaim bahwa return false;
kode tersebut tidak dapat dijangkau. Dan tampaknya benar, saya dapat menghapusnya dan mengkompilasi tanpa keluhan. Namun, bagi saya sepertinya tidak akan ada nilai kembali untuk jalur kode tempat pengecualian yang disebutkan dilemparkan.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
Apa kesalahan pemahaman saya di sini?
sumber
Dispose
secara eksplisit, tetapi tuliskanusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
blok berarti sesuatu yang lain dari yang Anda pikirkan.Jawaban:
Peringatan Penyusun (level 2) CS0162
Yang hanya mengatakan, Compiler cukup memahami melalui Analisis Statis sehingga tidak dapat dijangkau dan sepenuhnya menghilangkannya dari IL yang dikompilasi (karenanya peringatan Anda)
Catatan : Anda dapat membuktikan fakta ini kepada diri Anda sendiri dengan mencoba Menginjak ke Kode Tak Terjangkau dengan debugger, atau menggunakan Penjelajah IL
The
finally
dapat berjalan pada Exception , (meskipun samping) itu tidak mengubah fakta (dalam kasus ini) masih akan menjadi Exception Tertangkap . Ergo, yang terakhirreturn
tidak akan pernah terkena.Jika Anda ingin kode untuk melanjutkan ke terakhir
return
, satu-satunya pilihan Anda adalah untuk menangkap para Exception ;Jika tidak, biarkan saja apa adanya dan hapus file
return
.Contoh
Mengutip dokumentasi
coba-akhirnya (Referensi C #)
akhirnya
Saat menggunakan apa pun yang mendukung
IDisposable
antarmuka (yang dirancang untuk melepaskan sumber daya yang tidak terkelola), Anda dapat membungkusnya dalam sebuahusing
pernyataan. Kompilator akan menghasilkantry {} finally {}
panggilan internal danDispose()
objeksumber
Salah.
finally
tidak menelan pengecualian. Itu menghormatinya dan pengecualian akan dilemparkan seperti biasa. Ini hanya akan mengeksekusi kode pada akhirnya sebelum blok berakhir (dengan atau tanpa pengecualian).Jika Anda ingin pengecualian ditelan, Anda harus menggunakan
catch
blok tanpathrow
di dalamnya.sumber
return false
karena akan memunculkan pengecualian sebagai gantinya @EhsanSajjadPeringatannya adalah karena Anda tidak menggunakan
catch
dan metode Anda pada dasarnya ditulis seperti ini:Karena Anda
finally
hanya menggunakan untuk membuang, solusi yang disukai adalah menggunakanusing
pola:Itu cukup, untuk memastikan apa yang
Dispose
akan dipanggil. Ini dijamin akan disebut baik setelah keberhasilan pelaksanaan blok kode atau atas (sebelum) beberapacatch
turun dalam panggilan stack (panggilan orang tua turun, kan?).Jika bukan tentang membuang, maka
sudah cukup, karena Anda tidak perlu kembali
false
di akhir metode (baris itu tidak diperlukan). Metode Anda adalah hasil kembalian dari eksekusi perintah (true
ataufalse
) atau akan memunculkan pengecualian jika tidak .Pertimbangkan juga untuk menampilkan pengecualian sendiri dengan menggabungkan pengecualian yang diharapkan (lihat konstruktor InvalidOperationException ):
Ini biasanya digunakan untuk mengatakan sesuatu yang lebih berarti (berguna) kepada pemanggil daripada yang akan diceritakan oleh pengecualian panggilan bersarang.
Sering kali Anda tidak terlalu peduli dengan pengecualian yang tidak tertangani. Terkadang Anda perlu memastikan bahwa
finally
dipanggil meskipun pengecualian tidak ditangani. Dalam hal ini Anda cukup menangkapnya sendiri dan membuangnya kembali (lihat jawaban ini ):sumber
Sepertinya, Anda mencari sesuatu seperti ini:
Harap perhatikan, itu
finally
tidak menelan pengecualian apa punsumber
Anda tidak memiliki
catch
blok, jadi pengecualian masih dilempar, yang memblokir pengembalian.Ini salah, karena blok terakhir akan dieksekusi, dan kemudian akan ada pengecualian yang tidak tertangkap.
finally
blok digunakan untuk pembersihan, dan mereka tidak menangkap pengecualian. Pengecualian dilemparkan sebelum pengembalian, oleh karena itu, pengembalian tidak akan pernah tercapai, karena pengecualian dilemparkan sebelumnya.IDE Anda benar sehingga tidak akan pernah tercapai, karena pengecualian akan dibuang. Hanya
catch
blok yang dapat menangkap pengecualian.Membaca dari dokumentasi ,
Ini jelas menunjukkan bahwa akhirnya tidak dimaksudkan untuk menangkap pengecualian, dan Anda akan benar jika ada
catch
pernyataan kosong sebelumfinally
pernyataan itu.sumber
Ketika pengecualian dilemparkan, tumpukan akan melepas (eksekusi akan keluar dari fungsi) tanpa mengembalikan nilai, dan blok penangkap apa pun dalam bingkai tumpukan di atas fungsi akan menangkap pengecualian sebagai gantinya.
Karenanya,
return false
tidak akan pernah mengeksekusi.Coba berikan pengecualian secara manual untuk memahami aliran kontrol:
sumber
Pada kode Anda:
Ini adalah kelemahan dalam logika Anda karena
finally
blok tidak akan menangkap pengecualian dan tidak akan pernah mencapai pernyataan pengembalian terakhir.sumber
Pernyataan terakhir
return false
tidak dapat dijangkau, karena blok percobaan kehilangancatch
bagian yang akan menangani pengecualian, sehingga pengecualian muncul kembali setelahfinally
blok dan eksekusi tidak pernah mencapai pernyataan terakhir.sumber
Anda memiliki dua jalur pengembalian dalam kode Anda, yang kedua tidak dapat dijangkau karena yang pertama. Pernyataan terakhir di
try
blok Andareturn returnValue == 1;
memberikan pengembalian normal Anda, jadi Anda tidak akan pernah bisa mencapaireturn false;
di akhir blok metode.FWIW, urutan pemeriksaan yang terkait dengan
finally
blok tersebut adalah: ekspresi yang memberikan nilai pengembalian dalam blok percobaan akan dievaluasi terlebih dahulu, kemudian blok terakhir akan dieksekusi, dan kemudian nilai ekspresi yang dihitung akan dikembalikan (di dalam blok percobaan).Mengenai aliran pada pengecualian ... tanpa a
catch
,finally
akan dieksekusi setelah pengecualian sebelum pengecualian tersebut kemudian dibuang kembali dari metode; tidak ada jalur "kembali".sumber