Bayangkan kode berikut:
void DoThis()
{
if (!isValid) return;
DoThat();
}
void DoThat() {
Console.WriteLine("DoThat()");
}
Apakah boleh menggunakan metode pengembalian dalam void? Apakah ada penalti kinerja? Atau akan lebih baik jika menulis kode seperti ini:
void DoThis()
{
if (isValid)
{
DoThat();
}
}
Jawaban:
Pengembalian dalam metode void tidak buruk, adalah praktik umum untuk membalikkan
if
pernyataan untuk mengurangi penumpukan .Dan lebih sedikit bersarang pada metode Anda akan meningkatkan keterbacaan kode dan pemeliharaan.
Sebenarnya jika Anda memiliki metode void tanpa pernyataan return, kompilator akan selalu menghasilkan instruksi ret pada akhirnya.
sumber
Ada alasan bagus lainnya untuk menggunakan penjaga (sebagai lawan dari kode bersarang): Jika programmer lain menambahkan kode ke fungsi Anda, mereka bekerja di lingkungan yang lebih aman.
Mempertimbangkan:
void MyFunc(object obj) { if (obj != null) { obj.DoSomething(); } }
melawan:
void MyFunc(object obj) { if (obj == null) return; obj.DoSomething(); }
Sekarang, bayangkan programmer lain menambahkan baris: obj.DoSomethingElse ();
void MyFunc(object obj) { if (obj != null) { obj.DoSomething(); } obj.DoSomethingElse(); } void MyFunc(object obj) { if (obj == null) return; obj.DoSomething(); obj.DoSomethingElse(); }
Jelas ini adalah kasus yang sederhana, tetapi pemrogram telah menambahkan kerusakan ke program pada contoh pertama (kode bersarang). Dalam contoh kedua (keluar awal dengan penjaga), setelah Anda melewati penjaga, kode Anda aman dari penggunaan referensi null yang tidak disengaja.
Tentu, programmer hebat tidak membuat kesalahan seperti ini (sering). Tetapi mencegah lebih baik daripada mengobati - kita dapat menulis kode dengan cara yang menghilangkan potensi sumber kesalahan ini sepenuhnya. Penyusunan menambah kerumitan, jadi praktik terbaik merekomendasikan pemfaktoran ulang kode untuk mengurangi penyarangan.
sumber
Praktik buruk ??? Tidak mungkin. Faktanya, selalu lebih baik untuk menangani validasi dengan kembali dari metode paling awal jika validasi gagal. Jika tidak, ini akan menghasilkan sejumlah besar if & elses bersarang. Mengakhiri lebih awal meningkatkan keterbacaan kode.
Periksa juga tanggapan pada pertanyaan serupa: Haruskah saya menggunakan pernyataan return / continue daripada if-else?
sumber
Ini bukan praktik yang buruk (untuk semua alasan yang telah disebutkan). Namun, semakin banyak pengembalian yang Anda miliki dalam suatu metode, semakin besar kemungkinan itu harus dipecah menjadi metode logis yang lebih kecil.
sumber
Contoh pertama adalah menggunakan pernyataan penjaga. Dari Wikipedia :
Saya pikir memiliki sekelompok penjaga di bagian atas metode adalah cara yang dapat dimengerti untuk memprogram. Ini pada dasarnya mengatakan "jangan jalankan metode ini jika salah satu dari ini benar".
Jadi secara umum akan seperti ini:
void DoThis() { if (guard1) return; if (guard2) return; ... if (guardN) return; DoThat(); }
Saya pikir itu jauh lebih mudah dibaca:
void DoThis() { if (guard1 && guard2 && guard3) { DoThat(); } }
sumber
Tidak ada penalti kinerja, namun potongan kode kedua lebih mudah dibaca dan karenanya lebih mudah dipelihara.
sumber
Dalam kasus ini, contoh kedua Anda adalah kode yang lebih baik, tetapi itu tidak ada hubungannya dengan kembali dari fungsi void, itu hanya karena kode kedua lebih langsung. Tapi kembali dari fungsi kosong sama sekali tidak masalah.
sumber
Tidak apa-apa dan tidak ada 'penalti kinerja', tetapi jangan pernah menulis pernyataan 'jika' tanpa tanda kurung.
Selalu
if( foo ){ return; }
Ini jauh lebih mudah dibaca; dan Anda tidak akan pernah secara tidak sengaja berasumsi bahwa beberapa bagian kode ada dalam pernyataan itu padahal tidak.
sumber
{
. Ini sejajar{
dengan Anda}
di kolom yang sama, yang sangat membantu keterbacaan (jauh lebih mudah untuk menemukan kurung buka / tutup yang sesuai).if
pernyataan mana yang memerlukan kurung kurawal tutup akan mudah, dan dengan demikian memilikiif
pernyataan yang mengontrol satu pernyataan akan aman. Mendorong brace terbuka kembali ke garis denganif
menghemat garis spasi vertikal pada setiap pernyataan multiif
, tetapi akan membutuhkan penggunaan garis brace dekat yang tidak perlu.Saya akan tidak setuju dengan semua orang bodoh muda yang satu ini.
Menggunakan kembali di tengah metode, batal atau sebaliknya, adalah praktik yang sangat buruk, karena alasan yang diartikulasikan dengan cukup jelas, hampir empat puluh tahun yang lalu, oleh almarhum Edsger W. Dijkstra, dimulai dari "Pernyataan GOTO yang Dianggap Berbahaya ", dan dilanjutkan di" Pemrograman Terstruktur ", oleh Dahl, Dijkstra, dan Hoare.
Aturan dasarnya adalah bahwa setiap struktur kontrol, dan setiap modul, harus memiliki tepat satu entri dan satu pintu keluar. Pengembalian eksplisit di tengah modul melanggar aturan itu, dan membuatnya lebih sulit untuk bernalar tentang status program, yang pada gilirannya membuat lebih sulit untuk mengatakan apakah program itu benar atau tidak (yang merupakan properti yang jauh lebih kuat daripada "apakah itu tampak berfungsi atau tidak").
"Pernyataan GOTO Dianggap Berbahaya" dan "Pemrograman Terstruktur" memulai revolusi "Pemrograman Terstruktur" pada tahun 1970-an. Kedua bagian tersebut adalah alasan kami memiliki if-then-else, while-do, dan konstruksi kontrol eksplisit lainnya saat ini, dan mengapa pernyataan GOTO dalam bahasa tingkat tinggi ada di daftar Spesies Terancam Punah. (Pendapat pribadi saya adalah bahwa mereka harus ada dalam daftar Spesies Punah.)
Perlu dicatat bahwa Message Flow Modulator, perangkat lunak militer pertama yang PERNAH lulus pengujian penerimaan pada percobaan pertama, tanpa penyimpangan, pengabaian, atau kata-kata "ya, tetapi", ditulis dalam bahasa yang bahkan tidak memiliki pernyataan GOTO.
Perlu juga disebutkan bahwa Nicklaus Wirth mengubah semantik pernyataan RETURN di Oberon-07, versi terbaru dari bahasa pemrograman Oberon, membuatnya menjadi bagian akhir dari deklarasi prosedur yang diketik (yaitu, fungsi), daripada sebuah pernyataan yang dapat dieksekusi dalam tubuh fungsi. Penjelasan tentang perubahan mengatakan bahwa dia melakukannya justru karena bentuk sebelumnya WS pelanggaran prinsip satu-keluar dari Pemrograman Terstruktur.
sumber
Saat menggunakan penjaga, pastikan Anda mengikuti pedoman tertentu agar tidak membingungkan pembaca.
Contoh
// guards point you to the core intent void Remove(RayCastResult rayHit){ if(rayHit== RayCastResult.Empty) return ; rayHit.Collider.Parent.Remove(); } // no guards needed: function split into multiple cases int WonOrLostMoney(int flaw)=> flaw==0 ? 100 : flaw<10 ? 30 : flaw<20 ? 0 : -20 ;
sumber
Lempar pengecualian alih-alih tidak mengembalikan apa-apa saat objek nol, dll.
Metode Anda mengharapkan objek bukan null dan bukan kasusnya, jadi Anda harus membuang pengecualian dan membiarkan pemanggil menanganinya.
Tetapi kepulangan awal bukanlah praktik yang buruk sebaliknya.
sumber