Ketika Anda membuat metode ekstensi, Anda dapat, tentu saja, memanggilnya null
. Tapi, tidak seperti pemanggilan metode instan, memanggilnya dengan null tidak harus membuang NullReferenceException
-> Anda harus memeriksa dan membuangnya secara manual.
Untuk implementasi metode ekstensi Linq, Any()
Microsoft memutuskan bahwa mereka harus melempar ArgumentNullException
( https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs ).
Itu membuatku kesal harus menulis if( myCollection != null && myCollection.Any() )
Apakah saya salah, sebagai klien dari kode ini, untuk berharap bahwa misalnya ((int[])null).Any()
harus kembali false
?
c#
.net
linq
extension-method
lanjutkan ini
sumber
sumber
null |> Seq.isEmpty
melemparSystem.ArgumentNullException: Value cannot be null
. Harapannya tampaknya bahwa Anda tidak akan melewati nilai yang tidak ditentukan untuk sesuatu yang diharapkan ada, jadi itu masih merupakan pengecualian ketika Anda memiliki nol. Jika ini masalah inisialisasi, saya akan mulai dengan urutan kosong, bukannull
.null
ketika berhadapan dengan koleksi tetapi gunakan koleksi kosong dalam kasus tersebut.Any
hanya konsisten.Jawaban:
Saya punya tas dengan lima kentang di dalamnya. Apakah ada
.Any()
kentang di dalam tas?" Ya ," katamu.
<= true
Saya mengambil semua kentang dan memakannya. Apakah ada
.Any()
kentang di dalam tas?" Tidak ," katamu.
<= false
Aku benar-benar membakar kantong itu di api. Apakah ada
.Any()
kentang di dalam tas sekarang?" Tidak ada tas ."
<= ArgumentNullException
sumber
Pertama, tampaknya kode sumber itu akan melempar
ArgumentNullException
, bukanNullReferenceException
.Karena itu, dalam banyak kasus Anda sudah tahu bahwa koleksi Anda bukan nol, karena kode ini hanya dipanggil dari kode yang tahu bahwa koleksi tersebut sudah ada, sehingga Anda tidak perlu sering meletakkan cek nol di sana. Tetapi jika Anda tidak tahu bahwa itu ada, maka masuk akal untuk memeriksa sebelum memanggilnya
Any()
.Iya nih. Pertanyaan yang
Any()
dijawab adalah "apakah koleksi ini mengandung elemen?" Jika koleksi ini tidak ada, maka pertanyaannya sendiri tidak masuk akal; itu tidak dapat mengandung atau tidak mengandung apa pun, karena itu tidak ada.sumber
null
setara dengan set yang berisi set kosong (dan sebaliknya)?{ null }
dan{ {} }
harus setara. Saya menemukan itu menarik; Saya tidak bisa menghubungkannya sama sekali..Add
padanull
koleksi entah bagaimana membuat koleksi untuk kita juga?Null berarti informasi yang hilang, bukan elemen.
Anda mungkin mempertimbangkan untuk menghindari null secara lebih luas - misalnya, gunakan salah satu enumerables kosong bawaan untuk mewakili koleksi tanpa elemen, bukan nol.
Jika Anda mengembalikan nol dalam beberapa keadaan, Anda dapat mengubahnya untuk mengembalikan koleksi kosong. (Kalau tidak, jika Anda menemukan null dikembalikan oleh metode perpustakaan (bukan milik Anda), itu disayangkan, dan saya akan membungkusnya untuk dinormalisasi.)
Lihat juga https://stackoverflow.com/questions/1191919/what-does-linq-return-when-the-results-are-empty
sumber
null
tidak berarti tidak ada unsur yang merupakan masalah menggunakan konvensi yang masuk akal. Hanya berpikir tentang OLESTRINGS asli, di mana itu benar-benar tidak berarti itu.null
tidak berarti "informasi yang hilang".null
tidak memiliki interpretasi yang bermakna tunggal. Sebaliknya, itu adalah masalah bagaimana Anda memperlakukannya.null
kadang-kadang digunakan untuk "informasi yang hilang", tetapi juga untuk "tidak ada elemen", dan juga untuk "kesalahan terjadi" atau "tidak diinisialisasi" atau "informasi yang bertentangan" atau sesuatu yang sewenang-wenang dan ad-hoc.null
sangat sering digunakan untuk berarti "tidak ada data." Terkadang itu masuk akal. Lain waktu, tidak.Selain sintaksis bersyarat nol , ada teknik lain untuk mengatasi masalah ini: jangan biarkan variabel Anda tetap ada
null
.Pertimbangkan fungsi yang menerima koleksi sebagai parameter. Jika untuk tujuan fungsi,
null
dan kosong adalah setara, Anda dapat memastikan bahwa itu tidak pernah berisinull
di awal:Anda dapat melakukan hal yang sama ketika mengambil koleksi dari beberapa metode lain:
(Perhatikan bahwa dalam kasus di mana Anda memiliki kontrol atas fungsi seperti
GetWords
dannull
setara dengan koleksi kosong, lebih baik mengembalikan koleksi kosong di tempat pertama.)Sekarang Anda dapat melakukan operasi apa pun keinginan Anda pada koleksi. Ini sangat membantu jika Anda perlu melakukan banyak operasi yang akan gagal saat pengumpulan
null
, dan dalam kasus di mana Anda mendapatkan hasil yang sama dengan mengulang atau meminta kuota yang kosong, itu akan memungkinkan untuk menghilangkanif
kondisi sepenuhnya.sumber
Ya, hanya karena Anda berada di C # dan perilaku itu didefinisikan dan didokumentasikan dengan baik.
Jika Anda membuat perpustakaan Anda sendiri, atau jika Anda menggunakan bahasa yang berbeda dengan budaya pengecualian yang berbeda maka akan lebih masuk akal untuk mengharapkan false.
Secara pribadi saya merasa seolah-olah return false adalah pendekatan yang lebih aman yang membuat program Anda lebih kuat, tetapi setidaknya bisa diperdebatkan.
sumber
Jika pemeriksaan nol yang diulang mengganggu Anda, Anda bisa membuat metode ekstensi 'IsNullOrEmpty ()' Anda sendiri, untuk mencerminkan metode String dengan nama itu, dan membungkus kedua pemeriksaan nol dan panggilan .Any () menjadi satu panggilan.
Kalau tidak, solusinya, yang disebutkan oleh @ 17 dari 26 dalam komentar di bawah pertanyaan Anda, juga lebih pendek dari metode 'standar', dan cukup jelas bagi siapa pun yang akrab dengan sintaks null-kondisional baru.
sumber
?? false
bukan== true
. Ini akan tampak lebih eksplisit (bersih) bagi saya karena hanya menangani kasusnull
, dan tidak benar-benar bertele-tele lagi. Ditambah==
cek untuk Boolean biasanya memicu refleks muntah saya. =)myCollection?.Any()
cukup?myCollection?.Any()
secara efektif mengembalikan Boolean yang dapat dibatalkan daripada Boolean biasa (yaitu, bool? Bukan bool). Tidak ada konversi implisit dari bool? untuk bool, dan itu bool yang kita butuhkan dalam contoh khusus ini (untuk menguji sebagai bagian dariif
kondisi). Oleh karena itu, kita harus secara eksplisit membandingkan dengantrue
atau menggunakan operator penggabungan nol (??).?.
.==
akan benar-benar bekerja. Saya sudah tahu apa yang terjadi dengan Boolean secara intuitif padahal hanya bisatrue
ataufalse
; Aku bahkan tidak perlu memikirkannya. Tapinull
ikut campur, dan sekarang saya harus mencari tahu apakah itu==
benar.??
alih-alih hanya menghilangkannull
kasing, mengurangi kembali ketrue
danfalse
, yang sudah Anda mengerti segera. Adapun refleks muntah saya, ketika saya pertama kali melihatnya, insting langsung saya adalah menghapusnya karena biasanya tidak berguna, yang Anda tidak ingin terjadi.Jika Anda bertanya-tanya tentang harapan, Anda harus memikirkan niat.
null
berarti sesuatu yang sangat berbedaEnumerable.Empty<T>
Seperti yang disebutkan dalam jawaban Erik Eidt , ada perbedaan makna antara
null
dan koleksi kosong.Pertama mari kita melihat bagaimana mereka seharusnya digunakan.
Buku Pedoman Kerangka Kerja Desain: Konvensi, Idiom, dan Pola untuk Reusable .NET Library, Edisi ke-2 yang ditulis oleh arsitek Microsoft Krzysztof Cwalina dan Brad Abrams menyatakan praktik terbaik berikut ini:
Pertimbangkan memanggil metode yang pada akhirnya mendapatkan data dari database: Jika Anda menerima array kosong atau
Enumerable.Empty<T>
ini berarti ruang sampel Anda kosong, yaitu hasil Anda adalah set kosong . Menerimanull
dalam konteks ini, bagaimanapun, akan menandakan keadaan kesalahan .Dalam pemikiran yang sama dengan analogi kentang Dan Wilson , masuk akal untuk mengajukan pertanyaan tentang data Anda meskipun itu adalah set kosong . Tapi itu jauh lebih masuk akal, jika tidak ada set .
sumber
null
dan kosong dapat menghasilkan nilai balik yang sama untuk fungsi, tetapi itu tidak berartinull
dan kosong berarti hal yang persis sama dalam ruang lingkup panggilan.Ada banyak jawaban yang menjelaskan mengapa
null
dan kosong berbeda dan cukup banyak pendapat yang mencoba menjelaskan mengapa keduanya harus diperlakukan secara berbeda atau tidak. Namun Anda bertanya:Ini harapan yang masuk akal . Anda benar seperti orang lain yang mengadvokasi perilaku saat ini. Saya setuju dengan filosofi implementasi saat ini tetapi faktor pendorong tidak - hanya - didasarkan pada pertimbangan di luar konteks.
Mengingat bahwa
Any()
tanpa predikat pada dasarnyaCount() > 0
apa yang Anda harapkan dari cuplikan ini?Atau generik:
Saya kira Anda mengharapkan
NullReferenceException
.Any()
adalah metode ekstensi, itu harus lancar diintegrasikan dengan objek yang diperluas kemudian melemparkan pengecualian adalah hal yang paling tidak mengejutkan.Enumerable.Any(null)
dan di sana Anda pasti berharapArgumentNullException
. Ini adalah metode yang sama dan harus konsisten dengan - mungkin - hampir SEMUANYA dalam Kerangka.null
objek adalah kesalahan pemrograman , kerangka kerja seharusnya tidak menerapkan null sebagai nilai ajaib . Jika Anda menggunakannya seperti itu maka itu adalah tanggung jawab Anda untuk menghadapinya.Count()
tampaknya keputusan yang mudah makaWhere()
tidak. Bagaimana denganMax()
? Itu melempar pengecualian untuk daftar KOSONG, bukankah harus melempar juga untuknull
satu?Apa yang dilakukan perancang perpustakaan sebelum LINQ adalah untuk memperkenalkan metode eksplisit ketika
null
adalah nilai yang valid (misalnyaString.IsNullOrEmpty()
) maka mereka HARUS konsisten dengan filosofi desain yang ada . Yang mengatakan, bahkan jika cukup sepele untuk menulis, dua metodeEmptyIfNull()
danEmptyOrNull()
mungkin berguna.sumber
Jim seharusnya meninggalkan kentang di setiap kantong. Kalau tidak, aku akan membunuhnya.
Jim memiliki tas dengan lima kentang di dalamnya. Apakah ada
.Any()
kentang di dalam tas?"Ya," katamu. <= benar
Ok jadi Jim hidup saat ini.
Jim mengeluarkan semua kentang dan memakannya. Apakah ada. Setiap kentang di dalam tas?
"Tidak," katamu. <= salah
Waktunya membunuh Jim.
Jim benar-benar membakar tas itu ke dalam api. Apakah ada. Setiap kentang di dalam tas sekarang?
"Tidak ada tas." <= ArgumentNullException
Haruskah Jim hidup atau mati? Yah kami tidak mengharapkan ini jadi saya perlu putusan. Apakah membiarkan Jim lolos dengan ini bug atau tidak?
Anda dapat menggunakan anotasi untuk memberi sinyal bahwa Anda tidak tahan dengan shenanigans nol apa pun dengan cara ini.
Tetapi rantai alat Anda harus mendukungnya. Yang berarti Anda kemungkinan masih akan berakhir menulis cek.
sumber
Jika ini sangat mengganggu Anda, saya sarankan metode ekstensi sederhana.
Sekarang Anda bisa melakukan ini:
... dan bendera akan disetel ke
false
.sumber
return
pernyataan sebagai:return source ?? Enumerable.Empty<T>();
Ini adalah pertanyaan tentang metode ekstensi C # dan filosofi desainnya, jadi saya pikir cara terbaik untuk menjawab pertanyaan ini adalah dengan mengutip dokumentasi MSDN tentang tujuan metode ekstensi :
Singkatnya, metode ekstensi dirancang untuk menambahkan metode contoh ke jenis tertentu, bahkan ketika pengembang tidak dapat melakukannya secara langsung. Dan karena metode instance akan selalu menimpa metode ekstensi jika ada (jika dipanggil menggunakan sintaks metode instance), ini hanya boleh dilakukan jika Anda tidak bisa langsung menambahkan metode atau memperluas kelas. *
Dengan kata lain, metode ekstensi harus bertindak seperti metode instance, karena mungkin akhirnya dibuat metode instance oleh beberapa klien. Dan karena metode instance harus melempar jika objek yang dipanggil adalah
null
, demikian juga metode ekstensi.* Sebagai catatan tambahan, ini persis situasi yang dihadapi oleh para perancang LINQ: ketika C # 3.0 dirilis, sudah ada jutaan klien yang menggunakan
System.Collections.IEnumerable
danSystem.Collections.Generic.IEnumerable<T>
, baik dalam koleksi mereka maupun dalamforeach
loop. Kelas-kelas ini kembaliIEnumerator
benda-benda yang hanya memiliki dua metodeCurrent
danMoveNext
, sehingga menambahkan tambahan apapun metode instan diperlukan, sepertiCount
,Any
, dll, akan melanggar jutaan ini klien. Jadi, untuk menyediakan fungsionalitas ini (terutama karena dapat diimplementasikan dalam halCurrent
danMoveNext
dengan relatif mudah), mereka merilisnya sebagai metode ekstensi, yang dapat diterapkan ke semua yang ada saat iniIEnumerable
contoh dan juga dapat diimplementasikan oleh kelas dengan cara yang lebih efisien. Seandainya desainer C # memutuskan untuk merilis LINQ pada hari pertama, itu akan disediakan sebagai metode contohIEnumerable
, dan mereka mungkin akan merancang semacam sistem untuk menyediakan implementasi antarmuka standar dari metode tersebut.sumber
Saya pikir poin penting di sini adalah bahwa dengan mengembalikan false alih-alih melemparkan pengecualian, Anda mengaburkan informasi yang mungkin relevan bagi pembaca / pengubah kode Anda di masa mendatang.
Jika daftar tersebut mungkin nol, saya akan menyarankan memiliki jalur logika terpisah untuk itu, karena jika tidak di masa depan seseorang dapat menambahkan beberapa logika berbasis daftar (seperti add) ke yang lain {} dari if Anda, menghasilkan pengecualian yang tidak diinginkan bahwa mereka tidak punya alasan untuk memprediksi.
Keterbacaan dan pemeliharaan dapat mengalahkan 'Saya harus menulis kondisi ekstra' setiap saat.
sumber
Sebagai aturan umum, saya menulis sebagian besar kode saya untuk mengasumsikan bahwa penelepon bertanggung jawab untuk tidak memberikan saya data nol, sebagian besar untuk alasan yang diuraikan dalam Say No to Null (dan posting serupa lainnya). Konsep nol sering tidak dipahami dengan baik, dan untuk alasan itu, disarankan untuk menginisialisasi variabel Anda sebelumnya, sama praktisnya. Dengan asumsi Anda bekerja dengan API yang masuk akal, idealnya Anda tidak akan pernah mendapatkan nilai nol kembali, jadi Anda tidak perlu memeriksa nol. Inti dari nol, seperti yang dinyatakan oleh jawaban lain, adalah untuk memastikan bahwa Anda memiliki objek yang valid (mis. "Tas") untuk digunakan sebelum melanjutkan. Ini bukan fitur
Any
, tetapi fitur bahasadiri. Anda tidak dapat melakukan sebagian besar operasi pada objek null, karena tidak ada. Ini seperti jika saya meminta Anda untuk pergi ke toko di mobil saya, kecuali saya tidak memiliki mobil, jadi Anda tidak memiliki cara untuk menggunakan mobil saya untuk pergi ke toko. Tidak masuk akal untuk melakukan operasi pada sesuatu yang secara harfiah tidak ada.Ada beberapa kasus praktis untuk menggunakan null, seperti ketika Anda benar-benar tidak memiliki informasi yang diminta tersedia (misalnya jika saya bertanya kepada Anda berapa umur saya, pilihan yang paling mungkin bagi Anda untuk menjawab pada saat ini adalah "Saya tidak tahu ", yang merupakan nilai nol). Namun, dalam kebanyakan kasus, Anda setidaknya harus tahu apakah variabel Anda diinisialisasi atau tidak. Dan jika tidak, maka saya akan merekomendasikan Anda untuk memperketat kode Anda. Hal pertama yang saya lakukan dalam setiap program atau fungsi adalah menginisialisasi nilai sebelum saya menggunakannya. Jarang saya perlu memeriksa nilai nol, karena saya dapat menjamin bahwa variabel saya tidak nol. Merupakan kebiasaan yang baik untuk masuk, dan semakin sering Anda ingat untuk menginisialisasi variabel Anda, semakin sering Anda perlu memeriksa nol.
sumber