Apakah ada yang masih menggunakan [goto] di C # dan jika demikian, mengapa? [Tutup]

104

Saya bertanya-tanya apakah ada yang masih menggunakan sintaks kata kunci "goto" di C # dan alasan apa yang mungkin ada untuk melakukannya.

Saya cenderung melihat pernyataan apa pun yang menyebabkan pembaca melompati kode sebagai praktik buruk tetapi bertanya-tanya apakah ada skenario yang kredibel untuk menggunakan sintaks seperti itu?

Goto Definisi Kata Kunci

Brian Scott
sumber
3
apa maksudmu "diam"? Apakah ada periode waktu orang menggunakannya sepanjang waktu [di c #]?
Massif
4
@Massif: "masih" dimaksudkan untuk menekankan pendapat modern tentang penggunaan "goto" sebagai awal kode spaghetti dan kurangnya keterbacaan dalam kode sumber. Sangat jarang Anda melihat contoh kode termasuk kata kunci khusus ini, itulah sebabnya saya tertarik untuk bertanya sejak awal.
Brian Scott
50
Jika pembaca "melompat-lompat" kode tersebut adalah praktik yang buruk, apakah Anda juga menghindari "putus", "lanjutkan", "lempar", dan "kembali"? Mereka semua menyebabkan cabang dalam aliran kontrol, terkadang cabang non-lokal. "Lempar" bahkan tidak memberi tahu Anda kemana arahnya, tidak seperti Goto.
Eric Lippert
2
Saya gunakan gotountuk memutus lingkaran dan kembali ke pernyataan awal sesuai dengan kondisi tertentu
Nitin Sawant
3
Saya suka pergi. Saya mencoba menghindarinya karena kecenderungan orang mengatakan untuk menghindarinya karena membuat kode lebih sulit dibaca. Setelah mempelajari bahasa Assembly dan pernyataan cabang, saya pikir terkadang ada saatnya, mungkin membuat kode lebih mudah dibaca. Saya pikir banyak penggunaan dalam satu metode dan melompat terlalu jauh dalam kode dapat melakukan lebih banyak kerugian daripada kebaikan. Tetapi jika Anda berpikir sebuah goto akan bekerja dengan baik di sini, goto yang sederhana sesekali seharusnya tidak membuat Anda keluar dari cara Anda untuk menghindarinya hanya karena konsensus umum adalah untuk menghindarinya.
eaglei22

Jawaban:

93

Ada beberapa kasus (jarang) di mana goto sebenarnya dapat meningkatkan keterbacaan. Faktanya, dokumentasi yang Anda tautkan mencantumkan dua contoh:

Penggunaan goto yang umum adalah untuk mentransfer kontrol ke label switch-case tertentu atau label default dalam pernyataan switch.

Pernyataan goto juga berguna untuk keluar dari loop bersarang yang dalam.

Inilah contoh untuk yang terakhir:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

Tentu saja, ada cara lain untuk mengatasi masalah ini juga, seperti memfaktorkan ulang kode menjadi fungsi, menggunakan blok dummy di sekitarnya, dll. (Lihat pertanyaan ini untuk detailnya). Sebagai catatan tambahan, desainer bahasa Java memutuskan untuk melarang goto sepenuhnya dan memperkenalkan pernyataan break berlabel sebagai gantinya.

Heinzi
sumber
47
Biasanya saya akan mencoba untuk mem-refactor ini untuk menempatkan loop dalam metode terpisah yang saya dapat kembali dari ...
Jon Skeet
2
@ Heinzi - Saya belum melihat goto dijamin. Seperti yang dikatakan Jon, jika itu "dijamin", kode tersebut memohon untuk direfraktorisasi.
manojlds
29
berlabel istirahat, cara yang lebih panjang untuk mengatakan pergi karena melakukan hal aneh yang sama ....
Jesus Ramos
20
@Yesus tapi kemudian dengan pergi, Anda bisa pergi ke mana saja. Istirahat berlabel memastikan Anda berada tepat di luar loop.
mihsathe
1
Kecuali Anda sedang berpetualang dan menggunakan goto dengan alamat (saya pernah melihatnya dilakukan sebelumnya) maka masalah itu dikurangi. Dan saya ragu seseorang menggunakan hook jalan memutar di C # dan kode Java Anda untuk mengeksploitasi pernyataan goto.
Jesus Ramos
66

Saya ingat bagian ini

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

Untuk sesuatu seperti ini

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

Lihat Ini

V4Vendetta
sumber
17
Saya sebenarnya melihat ini sebagai alasan paling valid untuk menggunakan [goto]. Setidaknya dalam skenario ini meningkatkan keterbacaan bagi pemrogram yang tidak menyadari bahwa kasus jatuh satu sama lain tanpa pernyataan break.
Brian Scott
11
@Pramugari_id. Kecuali saya salah, pernyataan pertama tidak dapat dikompilasi di C #. Itu akan membantu pemahaman programmer.
Jodrell
2
V4Vendetta mengapa Anda memasukkan jeda pada cuplikan kode pertama ...? Lebih baik menunjukkannya tanpa jeda, jika tidak, kedua cuplikan tersebut melakukan hal yang berbeda. Alasan mengapa Anda membutuhkan goto di contoh kedua justru karena yang pertama tidak dapat dikompilasi di C # (seperti di C).
Stephen Holt
23

Saya menggunakannya secara ekstensif di Eduasync untuk menunjukkan jenis kode yang dihasilkan kompilator untuk Anda saat menggunakan metode asinkron di C # 5. Anda akan melihat hal yang sama di blok iterator.

Namun dalam kode "normal", saya tidak dapat mengingat kapan terakhir kali saya menggunakannya ...

Jon Skeet
sumber
1
dapatkah Anda memberikan contoh kecil mengapa pendekatan ini lebih disukai atau apakah itu hanya preferensi pribadi?
Brian Scott
1
@ Brian: Tidak terlalu jelas apa yang Anda maksud. Eduasync menunjukkan kode C # yang setara dengan apa yang dilakukan kompilator untuk Anda - dan menghasilkan kode yang menggunakan goto, secara efektif ...
Jon Skeet
9

goto sangat bagus untuk memecah banyak loop di mana break tidak akan berfungsi dengan baik (katakanlah pada kondisi kesalahan), dan seperti yang dikatakan Kragen, goto digunakan oleh kompiler untuk menghasilkan pernyataan switch dan beberapa hal lainnya juga.

Yesus Ramos
sumber
7
Tentunya "break" / "continue" adalah pendekatan yang lebih baik untuk manajemen loop daripada mengharuskan editor kode untuk melompat-lompat di sekitar kode sumber mencoba memahami di mana langkah selanjutnya terjadi?
Brian Scott
6
Tidak jika Anda memiliki loop bersarang.
Jesus Ramos
1
ok, saya bisa melihat ini sebagai skenario yang valid.
Brian Scott
1
Dalam kondisi kesalahan, Anda harus mempertimbangkan untuk membuat pengecualian.
Jodrell
6
Jika Anda ingin menangani kesalahan secara internal tanpa pengecualian, ini adalah cara yang valid untuk melakukannya.
Jesus Ramos
8

Saya tidak ingat pernah menggunakan goto. Tapi mungkin itu meningkatkan maksud loop selamanya yang Anda benar-benar tidak ingin keluar (tidak break, tetapi Anda masih bisa returnatau throw):

forever: {
  // ...
  goto forever;
}

Kemudian lagi, yang sederhana while (true)sudah cukup ...

Selain itu, Anda dapat menggunakan dalam situasi di mana Anda ingin iterasi pertama dari sebuah loop dimulai di tengah-tengah loop: lihat di sini sebagai contoh.

Jordão
sumber
The jawaban terkait berisi penggunaan "menarik" dari goto.. dan while(true) {..}bukan merupakan penggunaan yang menarik ..
user2864740
5

Kompilator menggunakan gotopernyataan dalam berbagai bagian kode yang dihasilkan, misalnya dalam jenis blok iterator yang dihasilkan (dihasilkan saat menggunakan yield returnkata kunci - Saya cukup yakin bahwa jenis serialisasi XML yang dihasilkan juga memiliki beberapa gotopernyataan di sana juga.

Lihat detail implementasi blok Iterator: mesin status yang dibuat secara otomatis untuk beberapa detail selengkapnya tentang mengapa / bagaimana compiler C # menangani ini.

Selain kode yang dihasilkan, tidak ada alasan yang baik untuk menggunakan gotopernyataan dalam kode normal - ini membuat kode lebih sulit untuk dipahami dan akibatnya lebih rentan terhadap kesalahan. Di sisi lain, menggunakan gotopernyataan dalam kode yang dihasilkan seperti ini dapat menyederhanakan proses pembuatan dan biasanya baik-baik saja karena tidak ada yang akan membaca (atau memodifikasi) kode yang dihasilkan dan tidak ada kemungkinan kesalahan dibuat karena mesin sedang melakukan penulisan.

Lihat Pernyataan Go-to yang dianggap berbahaya untuk argumen yang menentang gotoserta bagian klasik dari sejarah pemrograman.

Justin
sumber
4
Ini bodoh: ada beberapa kasus yang berguna, seperti yang digambarkan oleh jawaban lain. Entah Anda menggosoknya secara eksplisit, atau hanya mengatakan "itu salah" adalah, yah, salah.
o0 '.
@Lohoris Saya tidak membelinya - setiap contoh yang saya lihat di mana goto "meningkatkan keterbacaan" (termasuk jawabannya di sini) akan jauh lebih mudah dibaca setelah beberapa refactoring sederhana.
Justin
3
@Justin no, terkadang nested loop adalah cara paling alami untuk melakukan sesuatu, misalnya jika Anda melintasi array array.
o0 '.
6
@Justin tidak selalu lebih jelas untuk membuatnya menjadi sebuah fungsi. Anda memaksa sesuatu (memiliki fungsi) hanya untuk menghindari sesuatu yang Anda benci secara agama (menggunakan goto). Indikasi yang jelas untuk melakukan sesuatu yang salah.
o0 '.
3
Panggilan @Din Functions memiliki overhead. gototidak. Sesuatu untuk dipertimbangkan.
Dan Bechard
2

Prosesor menerapkan setidaknya satu instruksi lompatan dan saya yakin banyak pernyataan menggunakan itu dalam implementasi atau interpretasi mereka.

Salah satu hal baik tentang menggunakan bahasa generasi ke - 3 atau ke - 4 adalah detail fisik ini disarikan dari kita. Sementara kita harus memperhatikan hukum abstraksi bocor, saya pikir kita juga harus menggunakan alat kita sebagaimana mestinya ( maaf ). Jika saya menulis kode dan gotosepertinya ide yang bagus, sekarang saatnya untuk melakukan refactor. Tujuan dari bahasa terstruktur adalah untuk menghindari "lompatan" ini dan untuk menciptakan alur logis dalam rekayasa kami.

Saya harus menghindari penggunaan breaktetapi saya tidak bisa mengabaikan manfaat kinerja. Namun, jika saya memiliki loop bersarang yang saling membutuhkan break, inilah saatnya untuk melakukan refactor.

Jika ada yang bisa mengusulkan penggunaan gotoyang tampaknya lebih baik daripada refactoring, saya dengan senang hati akan menarik jawaban saya.

Saya harap saya tidak bersalah karena terburu-buru ke " gudang sepeda " di sini. Seperti yang dikatakan Kragen, apa yang cukup baik untuk Dijkstra sudah cukup baik untuk saya.

Jodrell
sumber
1
Mengambil sebuah dynamicobjek dan berjalan, itu adalah grafik objek yang berisi banyak kamus untuk mendapatkan nilai yang saya butuhkan. Tidak masuk akal untuk menggunakan metode yang memiliki parameter dynamicnamun mengharapkan bentuk objek yang tepat. Dengan kebagian untuk memecah beberapa lapisan dan terus berjalan melalui koleksi benda-benda ini. [Saya tidak memiliki tipe jadi saya tidak dapat memberikan akses yang lebih baik, jadi refleksi atau dinamis]
Chris Marisic
-6

Goto tidak pernah lebih baik. Dan lanjutkan, break (kecuali dalam switch / case), (multiple) return, dan throw juga harus dijaga seminimal mungkin. Anda tidak ingin melarikan diri dari tengah loop sarang. Anda selalu ingin pernyataan kontrol loop memiliki semua kontrol loop. Indentasi memiliki informasi, dan semua pernyataan ini membuang informasi itu. Anda mungkin juga menghapus semua indentasi.

Kirk Augustin
sumber
10
Anda ingin keluar dari perulangan jika tidak ada gunanya menjaga eksekusi perulangan. Jika tidak, Anda akan menghabiskan lebih banyak waktu pemrosesan dalam loop yang lebih lama tanpa alasan.
Skuld
12
@ Kirk, ini terdengar seperti opini daripada sesuatu yang kuantitatif?
Brian Scott