Saya telah melihat F # baru-baru ini, dan sementara saya tidak mungkin untuk melompat pagar dalam waktu dekat, itu pasti menyoroti beberapa area di mana C # (atau dukungan perpustakaan) dapat membuat hidup lebih mudah.
Secara khusus, saya sedang berpikir tentang kemampuan pencocokan pola F #, yang memungkinkan sintaks yang sangat kaya - jauh lebih ekspresif daripada saklar saat ini / yang setara dengan C #. Saya tidak akan mencoba memberikan contoh langsung (F # saya tidak sesuai), tetapi singkatnya itu memungkinkan:
- cocok dengan jenis (dengan pemeriksaan cakupan penuh untuk serikat yang didiskriminasi) [perhatikan ini juga menyimpulkan jenis untuk variabel terikat, memberikan akses anggota dll]
- cocok dengan predikat
- kombinasi di atas (dan mungkin beberapa skenario lain yang tidak saya sadari)
Meskipun akan menyenangkan bagi C # untuk akhirnya meminjam [ahem] sebagian dari kekayaan ini, untuk sementara saya telah melihat apa yang dapat dilakukan saat runtime - misalnya, cukup mudah untuk menyatukan beberapa objek untuk memungkinkan:
var getRentPrice = new Switch<Vehicle, int>()
.Case<Motorcycle>(bike => 100 + bike.Cylinders * 10) // "bike" here is typed as Motorcycle
.Case<Bicycle>(30) // returns a constant
.Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
.Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
.ElseThrow(); // or could use a Default(...) terminator
di mana getRentPrice adalah Func <Vehicle, int>.
[note - mungkin Switch / Kasing di sini adalah istilah yang salah ... tapi itu menunjukkan ide]
Bagi saya, ini jauh lebih jelas daripada yang setara menggunakan mengulangi if / else, atau conditional terner komposit (yang menjadi sangat berantakan untuk ekspresi non-sepele - kurung berlimpah). Ini juga menghindari banyak casting, dan memungkinkan untuk ekstensi sederhana (baik secara langsung atau melalui metode ekstensi) untuk pertandingan yang lebih spesifik, misalnya pertandingan InRange (...) yang sebanding dengan VB Select ... Case "x To y "penggunaan.
Saya hanya mencoba untuk mengukur apakah orang berpikir ada banyak manfaat dari konstruksi seperti di atas (tanpa adanya dukungan bahasa)?
Perhatikan juga bahwa saya telah bermain dengan 3 varian di atas:
- versi Fungsi <TSource, TValue> untuk evaluasi - sebanding dengan pernyataan kondisional ternary komposit
- versi Action <TSource> - dapat dibandingkan dengan if / else if / else if / else if / else
- versi Expression <Func <TSource, TValue >> - sebagai yang pertama, tetapi dapat digunakan oleh penyedia LINQ yang sewenang-wenang
Selain itu, menggunakan versi berbasis-Ekspresi memungkinkan penulisan ulang Expression-tree, pada dasarnya inline semua cabang menjadi Ekspresi bersyarat komposit tunggal, daripada menggunakan doa berulang-ulang. Saya belum memeriksanya baru-baru ini, tetapi dalam beberapa pengembangan Entitas Framework awal saya ingat ini diperlukan, karena tidak terlalu menyukai InvocationExpression. Ini juga memungkinkan penggunaan yang lebih efisien dengan LINQ-to-Objects, karena ia menghindari pemanggilan delegasi berulang - tes menunjukkan kecocokan seperti di atas (menggunakan formulir Ekspresi) yang bekerja pada kecepatan yang sama [sedikit lebih cepat, pada kenyataannya] dibandingkan dengan C # yang setara pernyataan bersyarat komposit. Untuk kelengkapan, versi berbasis Func <...> membutuhkan waktu 4 kali lebih lama daripada pernyataan kondisional C #, tetapi masih sangat cepat dan tidak mungkin menjadi hambatan utama dalam sebagian besar kasus penggunaan.
Saya menyambut setiap pemikiran / masukan / kritik / dll di atas (atau tentang kemungkinan dukungan bahasa C # lebih kaya ... di sini berharap ;-p).
sumber
switch-case
pernyataan. Jangan salah paham, saya pikir ini tempatnya dan saya mungkin akan mencari cara untuk mengimplementasikannya.Jawaban:
Saya tahu ini adalah topik lama, tetapi di c # 7 Anda dapat melakukannya:
sumber
Setelah mencoba melakukan hal-hal "fungsional" seperti itu di C # (dan bahkan mencoba buku tentang itu), saya sampai pada kesimpulan bahwa tidak, dengan beberapa pengecualian, hal-hal seperti itu tidak banyak membantu.
Alasan utamanya adalah bahasa-bahasa seperti F # mendapatkan banyak kekuatan dari benar-benar mendukung fitur-fitur ini. Bukan "Anda bisa melakukannya", tetapi "itu sederhana, jelas, itu diharapkan".
Misalnya, dalam pencocokan pola, Anda mendapatkan kompiler memberi tahu Anda jika ada pertandingan yang tidak lengkap atau ketika pertandingan lain tidak akan pernah mengenai. Ini kurang berguna untuk tipe open ended, tetapi ketika mencocokkan serikat yang didiskriminasi atau tupel, ini sangat bagus. Dalam F #, Anda mengharapkan orang untuk mencocokkan pola, dan itu langsung masuk akal.
"Masalahnya" adalah begitu Anda mulai menggunakan beberapa konsep fungsional, wajar jika Anda ingin melanjutkan. Namun, memanfaatkan tupel, fungsi, aplikasi metode parsial dan kari, pencocokan pola, fungsi bersarang, generik, dukungan monad, dll. Di C # menjadi sangat jelek, sangat cepat. Sangat menyenangkan, dan beberapa orang yang sangat pintar telah melakukan beberapa hal yang sangat keren di C #, tetapi sebenarnya menggunakannya terasa berat.
Apa yang akhirnya saya gunakan (lintas proyek) di C #:
** Namun perlu diperhatikan: Kurangnya generalisasi otomatis dan inferensi tipe benar-benar menghambat penggunaan bahkan fitur-fitur ini. **
Semua ini dikatakan, seperti orang lain sebutkan, di tim kecil, untuk tujuan tertentu, ya, mungkin mereka bisa membantu jika Anda terjebak dengan C #. Tetapi dalam pengalaman saya, mereka biasanya merasa lebih merepotkan daripada nilainya - YMMV.
Beberapa tautan lain:
sumber
Arguably alasan bahwa C # tidak membuatnya mudah untuk mengaktifkan tipe adalah karena itu terutama bahasa berorientasi objek, dan cara yang 'benar' untuk melakukan ini dalam istilah berorientasi objek akan mendefinisikan metode GetRentPrice pada Kendaraan dan menimpanya di kelas turunan.
Yang mengatakan, saya telah menghabiskan sedikit waktu bermain dengan multi-paradigma dan bahasa fungsional seperti F # dan Haskell yang memiliki jenis kemampuan ini, dan saya telah menemukan sejumlah tempat di mana itu akan berguna sebelumnya (misalnya ketika Anda tidak menulis jenis yang perlu Anda aktifkan sehingga Anda tidak dapat menerapkan metode virtual pada mereka) dan itu adalah sesuatu yang saya akan sambut dengan bahasa bersama dengan serikat yang didiskriminasi.
[Sunting: Bagian yang dihapus tentang kinerja seperti yang ditunjukkan oleh Marc bisa mengalami hubungan pendek]
Masalah potensial lainnya adalah kegunaan - jelas dari panggilan terakhir apa yang terjadi jika pertandingan gagal memenuhi persyaratan apa pun, tetapi bagaimana perilaku jika cocok dengan dua atau lebih kondisi? Haruskah itu membuat pengecualian? Haruskah mengembalikan pertandingan pertama atau terakhir?
Suatu cara yang saya cenderung gunakan untuk memecahkan masalah semacam ini adalah dengan menggunakan bidang kamus dengan jenis sebagai kunci dan lambda sebagai nilainya, yang cukup singkat untuk membangun menggunakan sintaksis objek initializer; Namun, ini hanya memperhitungkan jenis beton dan tidak memungkinkan predikat tambahan sehingga mungkin tidak cocok untuk kasus yang lebih kompleks. [Catatan tambahan - jika Anda melihat output dari kompiler C # itu sering mengonversi pernyataan beralih ke tabel lompatan berbasis kamus, jadi sepertinya tidak ada alasan yang bagus mengapa ia tidak dapat mendukung pengaktifan jenis]
sumber
Saya tidak berpikir perpustakaan semacam ini (yang bertindak seperti ekstensi bahasa) cenderung mendapat penerimaan luas, tetapi menyenangkan untuk dimainkan, dan bisa sangat berguna bagi tim kecil yang bekerja di domain tertentu di mana ini berguna. Sebagai contoh, jika Anda menulis banyak 'aturan / logika bisnis' yang melakukan tes jenis sewenang-wenang seperti ini dan yang lainnya, saya bisa melihat bagaimana itu akan berguna.
Saya tidak tahu apakah ini akan menjadi fitur bahasa C # (sepertinya ragu, tapi siapa yang bisa melihat masa depan?).
Untuk referensi, F # yang sesuai kira-kira:
dengan asumsi Anda mendefinisikan hierarki kelas di sepanjang baris
sumber
Untuk menjawab pertanyaan Anda, ya saya pikir konstruksi sintaksis pencocokan pola berguna. I untuk satu ingin melihat dukungan sintaksis di C # untuk itu.
Berikut ini adalah implementasi saya dari kelas yang menyediakan (hampir) sintaksis yang sama seperti yang Anda jelaskan
Berikut ini beberapa kode tes:
sumber
Pencocokan pola (seperti dijelaskan di sini ), tujuannya adalah mendekonstruksi nilai sesuai dengan spesifikasi tipenya. Namun, konsep kelas (atau tipe) di C # tidak setuju dengan Anda.
Tidak ada yang salah dengan desain bahasa multi-paradigma, sebaliknya, itu sangat bagus untuk memiliki lambda di C #, dan Haskell dapat melakukan hal-hal penting seperti misalnya IO. Tapi itu bukan solusi yang sangat elegan, tidak dalam mode Haskell.
Tetapi karena bahasa pemrograman prosedural berurutan dapat dipahami dalam hal kalkulus lambda, dan C # cocok dengan parameter dari bahasa prosedural berurutan, itu cocok. Tetapi, mengambil sesuatu dari konteks fungsional murni katakanlah Haskell, dan kemudian menempatkan fitur itu ke dalam bahasa yang tidak murni, well, melakukan hal itu, tidak akan menjamin hasil yang lebih baik.
Maksud saya adalah ini, apa yang membuat tick pola yang cocok dikaitkan dengan desain bahasa dan model data. Karena itu, saya tidak percaya pencocokan pola menjadi fitur yang berguna dari C # karena tidak menyelesaikan masalah C # khas juga tidak cocok dengan paradigma pemrograman imperatif.
sumber
IMHO cara OO melakukan hal-hal seperti itu adalah pola Pengunjung. Metode anggota pengunjung Anda hanya bertindak sebagai konstruksi kasus dan Anda membiarkan bahasa itu sendiri menangani pengiriman yang sesuai tanpa harus "mengintip" jenis.
sumber
Meskipun tidak terlalu 'C-sharpey' untuk mengaktifkan tipe, saya tahu bahwa konstruk akan sangat membantu dalam penggunaan umum - saya memiliki setidaknya satu proyek pribadi yang dapat menggunakannya (meskipun ATM yang dikelola). Apakah ada banyak masalah kinerja kompilasi, dengan pohon ekspresi menulis ulang?
sumber
Saya pikir ini terlihat sangat menarik (+1), tetapi satu hal yang harus diperhatikan: kompiler C # cukup bagus dalam mengoptimalkan pernyataan switch. Tidak hanya untuk hubungan arus pendek - Anda mendapatkan IL yang sama sekali berbeda tergantung pada berapa banyak kasus yang Anda miliki dan seterusnya.
Contoh spesifik Anda memang melakukan sesuatu yang menurut saya sangat berguna - tidak ada sintaks yang setara dengan kasus per jenis, seperti (misalnya)
typeof(Motorcycle)
bukan konstanta.Ini semakin menarik dalam aplikasi dinamis - logika Anda di sini bisa dengan mudah digerakkan oleh data, memberikan eksekusi gaya 'mesin-aturan'.
sumber
Anda dapat mencapai apa yang Anda inginkan dengan menggunakan perpustakaan yang saya tulis, bernama OneOf
Keuntungan utama atas
switch
(danif
danexceptions as control flow
) adalah bahwa ia aman saat kompilasi - tidak ada penangan default atau gagalAda di Nuget dan menargetkan net451 dan netstandard1.6
sumber