Catatan: Pertanyaan ini ditanyakan sebelum pengenalan yang .?
operator dalam C # 6 / Visual Studio 2015 .
Kita semua pernah ke sana, kita memiliki beberapa properti dalam seperti cake.frosting.berries.loader yang perlu kita periksa apakah itu nol sehingga tidak ada pengecualian. Cara yang harus dilakukan adalah menggunakan pernyataan hubungan arus pendek
if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...
Ini tidak sepenuhnya elegan, dan mungkin harus ada cara yang lebih mudah untuk memeriksa seluruh rantai dan melihat apakah itu muncul terhadap variabel null / properti.
Apakah mungkin menggunakan beberapa metode ekstensi atau apakah itu fitur bahasa, atau itu hanya ide yang buruk?
Jawaban:
Kami telah mempertimbangkan untuk menambah operasi baru "?." ke bahasa yang memiliki semantik yang Anda inginkan. (Dan itu telah ditambahkan sekarang; lihat di bawah.) Yaitu, Anda akan mengatakan
dan kompiler akan menghasilkan semua pemeriksaan arus pendek untuk Anda.
Itu tidak membuat bar untuk C # 4. Mungkin untuk versi bahasa hipotetis masa depan.
Update (2014): The
?.
operator sekarang direncanakan untuk Roslyn rilis compiler berikutnya. Perhatikan bahwa masih ada beberapa perdebatan tentang analisis sintaksis dan semantik yang tepat dari operator.Pembaruan (Juli 2015): Visual Studio 2015 telah dirilis dan dikirimkan dengan kompiler C # yang mendukung operator null-kondisional
?.
dan?[]
.sumber
Saya terinspirasi oleh pertanyaan ini untuk mencoba dan mencari tahu bagaimana pemeriksaan nol dalam seperti ini dapat dilakukan dengan sintaks yang lebih mudah / lebih cantik menggunakan pohon ekspresi. Sementara saya setuju dengan jawaban yang menyatakan bahwa itu mungkin desain yang buruk jika Anda sering perlu mengakses instance jauh di dalam hierarki, saya juga berpikir bahwa dalam beberapa kasus, seperti presentasi data, itu bisa sangat berguna.
Jadi saya membuat metode ekstensi, yang akan memungkinkan Anda untuk menulis:
Ini akan mengembalikan Berries jika tidak ada bagian dari ekspresi yang nol. Jika null ditemukan, null dikembalikan. Ada beberapa peringatan, dalam versi saat ini hanya akan bekerja dengan akses anggota yang sederhana, dan hanya bekerja pada .NET Framework 4, karena menggunakan metode MemberExpression.Update, yang baru di v4. Ini adalah kode untuk metode ekstensi IfNotNull:
Ini bekerja dengan memeriksa pohon ekspresi yang mewakili ekspresi Anda, dan mengevaluasi bagian-bagian satu demi satu; setiap kali memeriksa bahwa hasilnya tidak nol.
Saya yakin ini dapat diperluas sehingga ekspresi lain selain MemberExpression didukung. Anggap ini sebagai kode pembuktian konsep, dan harap diingat bahwa akan ada penalti performa dengan menggunakannya (yang mungkin tidak akan menjadi masalah dalam banyak kasus, tetapi jangan menggunakannya dalam lingkaran ketat :-))
sumber
DynamicInvoke
sana. Saya dengan religius menghindarinya :)Saya telah menemukan ekstensi ini sangat berguna untuk skenario bersarang yang mendalam.
Ini adalah ide yang saya dapatkan dari operator penggabungan nol dalam C # dan T-SQL. Yang menyenangkan adalah bahwa tipe pengembalian selalu menjadi tipe pengembalian properti dalam.
Dengan begitu Anda dapat melakukan ini:
... atau sedikit variasi di atas:
Itu bukan sintaks terbaik yang saya tahu, tetapi itu berhasil.
sumber
Selain melanggar Hukum Demeter, seperti yang telah ditunjukkan oleh Mehrdad Afshari, menurut saya Anda perlu "pemeriksaan nol dalam" untuk logika keputusan.
Ini paling sering terjadi ketika Anda ingin mengganti objek kosong dengan nilai default. Dalam hal ini Anda harus mempertimbangkan menerapkan Pola Objek Null . Ini bertindak sebagai stand-in untuk objek nyata, memberikan nilai default dan metode "non-aksi".
sumber
Pembaruan: Dimulai dengan Visual Studio 2015, kompiler C # (versi bahasa 6) sekarang mengenali
?.
operator, yang membuat "pemeriksaan nol dalam" menjadi mudah. Lihat jawaban ini untuk detailnya.Selain mendesain ulang kode Anda, seperti yang disarankan oleh jawaban yang dihapus ini , pilihan lain (walaupun mengerikan) adalah menggunakan
try…catch
blok untuk melihat apakahNullReferenceException
terjadi suatu saat selama pencarian properti mendalam tersebut.Saya pribadi tidak akan melakukan ini karena alasan berikut:
NullReferenceException
Mungkin seharusnya tidak pernah ditangkap secara eksplisit. (Lihat pertanyaan ini .)Ini hampir pasti harus menjadi fitur bahasa (yang tersedia dalam C # 6 dalam bentuk
.?
dan?[]
operator), kecuali C # sudah memiliki evaluasi malas yang lebih canggih, atau kecuali jika Anda ingin menggunakan refleksi (yang mungkin juga bukan ide yang bagus untuk alasan kinerja dan keamanan tipe).Karena tidak ada cara untuk hanya beralih
cake.frosting.berries.loader
ke fungsi (itu akan dievaluasi dan melempar pengecualian referensi nol), Anda harus menerapkan metode pencarian umum dengan cara berikut: Dibutuhkan objek dan nama properti untuk menengadah:(Catatan: kode diedit.)
Anda dengan cepat melihat beberapa masalah dengan pendekatan seperti itu. Pertama, Anda tidak mendapatkan keamanan tipe apa pun dan kemungkinan tinju nilai properti dari tipe sederhana. Kedua, Anda dapat kembali
null
jika terjadi kesalahan, dan Anda harus memeriksa ini di fungsi panggilan Anda, atau Anda melempar pengecualian, dan Anda kembali ke tempat Anda memulai. Ketiga, mungkin lambat. Keempat, terlihat lebih buruk dari apa yang Anda mulai.Saya akan tetap dengan:
atau pergi dengan jawaban di atas oleh Mehrdad Afshari.
PS: Dulu ketika saya menulis jawaban ini, saya jelas tidak mempertimbangkan pohon ekspresi untuk fungsi lambda; lihat misalnya jawaban @driis untuk solusi ke arah ini. Ini juga didasarkan pada semacam refleksi dan karenanya mungkin tidak berkinerja sebaik solusi yang lebih sederhana (
if (… != null & … != null) …
), tetapi mungkin dinilai lebih baik dari sudut pandang sintaksis.sumber
Sementara jawaban driis menarik, saya pikir itu kinerja yang terlalu mahal. Daripada mengkompilasi banyak delegasi, saya lebih suka mengkompilasi satu lambda per path properti, cache dan kemudian retvoke banyak jenis.
NullCoalesce di bawah tidak hanya itu, ia mengembalikan ekspresi lambda baru dengan cek nol dan pengembalian default (TResult) jika ada jalur yang null.
Contoh:
Akan mengembalikan ekspresi
Kode:
sumber
Salah satu pilihan adalah menggunakan Null Object Patten, jadi alih-alih memiliki nol ketika Anda tidak memiliki kue, Anda memiliki NullCake yang mengembalikan NullFosting dll. Maaf saya tidak pandai menjelaskan ini tetapi orang lain, lihat
sumber
Saya juga sering berharap untuk sintaksis yang lebih sederhana! Itu menjadi sangat jelek ketika Anda memiliki nilai metode-pengembalian-yang mungkin nol, karena Anda perlu variabel tambahan (misalnya:
cake.frosting.flavors.FirstOrDefault().loader
:)Namun, inilah alternatif yang lumayan yang saya gunakan: buat metode pembantu Null-Safe-Chain. Saya menyadari bahwa ini sangat mirip dengan jawaban John di atas (dengan
Coal
metode ekstensi) tetapi saya merasa lebih mudah dan kurang mengetik. Begini tampilannya:Inilah implementasinya:
Saya juga membuat beberapa overload (dengan 2 hingga 6 parameter), serta overload yang memungkinkan rantai diakhiri dengan tipe-nilai atau default. Ini bekerja sangat baik untuk saya!
sumber
Ada proyek Mungkin CodePlex yang Implements Mungkin atau IfNotNull menggunakan lambdas untuk ekspresi yang mendalam di C #
Contoh penggunaan:
Tautan itu disarankan dalam pertanyaan serupa. Bagaimana cara memeriksa nol di ekspresi lambda yang dalam?
sumber
Seperti yang disarankan di John Leidegren 's jawaban , salah satu pendekatan untuk kerja-sekitar ini adalah dengan menggunakan metode penyuluhan dan delegasi. Menggunakannya bisa terlihat seperti ini:
Implementasinya berantakan karena Anda harus membuatnya bekerja untuk tipe nilai, tipe referensi, dan tipe nilai nullable. Anda dapat menemukan implementasi lengkap di Timwi 's jawaban untuk Apa cara yang tepat untuk memeriksa nilai null? .
sumber
Atau Anda dapat menggunakan refleksi :)
Fungsi refleksi:
Pemakaian:
Kasus Saya (mengembalikan DBNull.Value alih-alih nol dalam fungsi refleksi):
sumber
Coba kode ini:
sumber
Saya memposting ini tadi malam dan kemudian seorang teman menunjuk saya ke pertanyaan ini. Semoga ini bisa membantu. Anda kemudian dapat melakukan sesuatu seperti ini:
Baca posting blog selengkapnya di sini .
Teman yang sama juga menyarankan agar Anda menonton ini .
sumber
Expression
jika Anda hanya akan mengkompilasi dan menangkap? Cukup gunakan aFunc<T>
.Saya sedikit memodifikasi kode dari sini untuk membuatnya berfungsi untuk pertanyaan yang diajukan:
Dan ya, ini mungkin bukan solusi optimal karena mencoba / menangkap implikasi kinerja tetapi berfungsi:>
Pemakaian:
sumber
Di mana Anda perlu mencapai ini, lakukan ini:
Pemakaian
atau
Implementasi kelas pembantu
sumber
Saya suka pendekatan yang diambil oleh Objective-C:
"Bahasa Objective-C mengambil pendekatan lain untuk masalah ini dan tidak memanggil metode pada nol tetapi sebaliknya mengembalikan nol untuk semua doa seperti itu."
sumber