Saya selalu menggunakan Nullable<>.HasValue
karena saya menyukai semantik. Namun, baru-baru ini saya sedang mengerjakan basis kode orang lain yang sudah ada di mana mereka menggunakannya Nullable<> != null
secara eksklusif.
Apakah ada alasan untuk menggunakan salah satu dari yang lain, atau itu murni preferensi?
int? a; if (a.HasValue) // ...
vs.
int? b; if (b != null) // ...
HasValue
karena saya pikir kata-kata cenderung lebih mudah dibaca daripada simbol. Semua terserah Anda, dan apa yang cocok dengan gaya Anda saat ini..HasValue
lebih masuk akal karena menunjukkan jenis adalah tipeT?
daripada jenis yang dapat dibatalkan seperti string.Jawaban:
Kompiler menggantikan perbandingan nol dengan panggilan ke
HasValue
, jadi tidak ada perbedaan nyata. Lakukan saja yang lebih mudah dibaca / lebih masuk akal bagi Anda dan kolega Anda.sumber
int? x = null
memberi saya ilusi bahwa instance nullable adalah tipe referensi. Tetapi kenyataannya adalah bahwa Nullable <T> adalah tipe nilai. Rasanya saya akan mendapatkan NullReferenceException untuk melakukan:int? x = null; Use(x.HasValue)
.Nullable<int>
sajaint?
.Saya lebih suka
(a != null)
agar sintaks cocok dengan jenis referensi.sumber
Nullable<>
ini bukan tipe referensi.HasValue
karena lebih mudah dibaca daripada!= null
Saya melakukan riset tentang hal ini dengan menggunakan metode yang berbeda untuk menetapkan nilai ke int nullable. Inilah yang terjadi ketika saya melakukan berbagai hal. Harus menjelaskan apa yang terjadi. Perlu diingat:
Nullable<something>
atau stenosomething?
adalah struct yang tampaknya dikompilasi oleh banyak kompiler agar kita gunakan dengan null seolah-olah itu adalah kelas.Seperti yang akan Anda lihat di bawah,
SomeNullable == null
danSomeNullable.HasValue
akan selalu mengembalikan yang diharapkan benar atau salah. Meskipun tidak diperlihatkan di bawah,SomeNullable == 3
valid juga (dengan asumsi SomeNullable adalah anint?
).Sementara
SomeNullable.Value
membuat kita error jika kita ditugaskannull
untukSomeNullable
. Ini sebenarnya satu-satunya kasus di mana nullables dapat menyebabkan masalah bagi kami, berkat kombinasi operator yang kelebihan beban, kelebihan muatanobject.Equals(obj)
metode, dan optimisasi kompiler dan bisnis monyet.Berikut ini adalah deskripsi dari beberapa kode yang saya jalankan, dan output apa yang dihasilkan oleh label:
Oke, mari kita coba metode inisialisasi selanjutnya:
Semua sama seperti sebelumnya. Perlu diingat bahwa menginisialisasi dengan
int? val = new int?(null);
, dengan null yang diteruskan ke konstruktor, akan menghasilkan kesalahan waktu COMPILE, karena VALUE objek yang dapat dibatalkan TIDAK BISA nullable. Hanya objek pembungkus itu sendiri yang bisa sama dengan nol.Demikian juga, kami akan mendapatkan kesalahan waktu kompilasi dari:
belum lagi itu
val.Value
adalah properti baca-saja, artinya kita bahkan tidak bisa menggunakan sesuatu seperti:tetapi sekali lagi, operator konversi implisit berlebih polimorf mari kita lakukan:
Tidak perlu khawatir tentang polisom apa pun yang bisa menahan, asalkan berfungsi dengan benar? :)
sumber
Nullable<X>
VisualStudio 2013 dan F12, Anda akan melihat bahwa itu hanya kelebihan konversi ke dan dariX
, danEquals(object other)
metode. Namun, saya pikir operator == menggunakan metode itu secara default, jadi efeknya sama. Sebenarnya saya bermaksud memperbarui jawaban ini atas fakta itu untuk sementara waktu sekarang, tetapi saya malas dan / atau sibuk. Komentar ini harus dilakukan untuk saat ini :)int? val = 42; val.GetType() == typeof(int)
). Jadi tidak hanya nullable struct yang dapat sama dengan null, itu juga sering tidak nullable sama sekali! : D Dengan cara yang sama, ketika Anda memasukkan nilai nullable, Anda sedang bertinjuint
, tidakint?
- dan ketika nilaiint?
tersebut tidak memiliki nilai, Anda mendapatkannull
alih-alih nilai nullable kotak. Ini pada dasarnya berarti jarang ada overhead dari menggunakan nullable dengan benar :)Null
suatu jenis .NET? Bisakah Anda menunjuk ke bagian dalam spesifikasi CLR / C # di mana itu dikatakan? Nullables didefinisikan dengan baik dalam spesifikasi CLR, perilaku mereka bukan "implementasi abstraksi" - itu adalah kontrak . Tetapi jika yang terbaik yang dapat Anda lakukan adalah serangan ad hominem, nikmatilah diri Anda.Di VB.Net. JANGAN gunakan "IsNot Nothing" saat Anda dapat menggunakan ".HasValue". Saya baru saja memecahkan "Operasi dapat membuat kestabilan runtime" kesalahan trust Sedang dengan mengganti "IsNot Nothing" dengan ".HasValue" Di satu tempat. Saya tidak begitu mengerti mengapa, tetapi ada sesuatu yang terjadi secara berbeda di kompiler. Saya akan berasumsi bahwa "! = Null" di C # mungkin memiliki masalah yang sama.
sumber
HasValue
karena mudah dibaca.IsNot Nothing
benar-benar ekspresi jelek (karena negasi ganda).Jika Anda menggunakan LINQ dan ingin menjaga kode Anda pendek, saya sarankan untuk selalu menggunakan
!=null
Dan inilah sebabnya:
Bayangkan kita memiliki beberapa kelas
Foo
dengan variabel ganda nullableSomeDouble
Jika di suatu tempat dalam kode kita, kita ingin mendapatkan semua Foo dengan nilai SomeDouble non null dari koleksi Foo (dengan asumsi beberapa foo dalam koleksi bisa juga nol), kita berakhir dengan setidaknya tiga cara untuk menulis fungsi kita (jika kita gunakan C # 6):
Dan dalam situasi seperti ini saya sarankan untuk selalu mencari yang lebih pendek
sumber
foo?.SomeDouble.HasValue
adalah kesalahan waktu kompilasi (bukan "lemparan" dalam terminologi saya) dalam konteks itu karena tipenya adalahbool?
, bukan hanyabool
. (.Where
Metode ini menginginkan aFunc<Foo, bool>
.) Hal ini diperbolehkan untuk dilakukan(foo?.SomeDouble).HasValue
, tentu saja, karena itu memiliki tipebool
. Inilah yang baris pertama Anda "diterjemahkan" secara internal oleh kompiler C # (setidaknya secara formal).Jawaban umum dan aturan praktis: jika Anda memiliki pilihan (misalnya menulis serializers khusus) untuk memproses Nullable dalam pipa yang berbeda dari
object
- dan menggunakan properti spesifik mereka - lakukan dan gunakan properti spesifik Nullable. Jadi dari sudut pandang pemikiran yang konsistenHasValue
harus lebih disukai. Pemikiran yang konsisten dapat membantu Anda menulis kode yang lebih baik agar tidak menghabiskan terlalu banyak waktu dalam perincian. Misalnya ada metode kedua akan berkali-kali lebih efektif (kebanyakan karena kompiler inlining dan tinju tetapi angka masih sangat ekspresif):Tes patokan:
Kode benchmark:
https://github.com/dotnet/BenchmarkDotNet digunakan
PS . Orang mengatakan bahwa saran "lebih memilih HasValue karena pemikiran yang konsisten" tidak berhubungan dan tidak berguna.Bisakah Anda memprediksi kinerja ini?
Orang-orang PPS terus minus tetapi tidak ada yang mencoba memprediksi kinerja
CheckNullableGenericImpl
. Dan ada compiler tidak akan membantu Anda mengganti!=null
denganHasValue
.HasValue
harus digunakan secara langsung jika Anda tertarik dengan kinerja.sumber
CheckObjectImpl
Kotak Anda dapat dibatalkan menjadiobject
, sedangkanCheckNullableImpl
tidak menggunakan tinju. Dengan demikian perbandingannya sangat tidak tepat. Bukan hanya itu bukan ongkos, itu juga tidak berguna karena, seperti disebutkan dalam jawaban yang diterima , kompiler menulis ulang!=
untukHasValue
tetap.Nullable<T>
, Anda melakukannya (dengan meninju menjadiobject
). Ketika Anda menerapkan!= null
dengan nullable di sebelah kiri, tinju tidak terjadi karena dukungan!=
untuk nullables bekerja di tingkat kompiler. Ini berbeda ketika Anda menyembunyikan nullable dari kompiler dengan terlebih dahulu memasukkannya ke dalamobject
. BaikCheckObjectImpl(object o)
atau patokan Anda masuk akal pada prinsipnya.CheckObjectImpl
dengan yang tubuh di dalamCheckObject
. Namun komentar terakhir Anda mengungkapkan bahwa Anda sebenarnya memiliki pertanyaan yang sangat berbeda ketika Anda memutuskan untuk menjawab pertanyaan berusia 8 tahun ini, yang membuat jawaban Anda menyesatkan dalam konteks pertanyaan awal. Bukan itu yang ditanyakan OP.what is faster != or HasValue
. Dia sampai pada pertanyaan ini, menelusuri jawaban Anda, menghargai tolok ukur Anda dan berkata, "Wah, saya tidak akan pernah menggunakan!=
karena jelas jauh lebih lambat!" Itu adalah kesimpulan yang sangat salah yang kemudian dia akan lanjutkan menyebar. Itulah mengapa saya percaya jawaban Anda berbahaya - jawaban itu menjawab pertanyaan yang salah dan karenanya menarik kesimpulan yang salah di dalam pembaca yang tidak curiga. Pertimbangkan apa yang terjadi ketika Anda mengubah AndaCheckNullableImpl
untuk juga menjadireturn o != null;
Anda akan mendapatkan hasil benchmark yang sama.!=
danHasValue
padahal sebenarnya menunjukkan perbedaan antaraobject o
danT? o
. Jika Anda melakukan apa yang saya menyarankan, yaitu, menulis ulangCheckNullableImpl
sebagaipublic static bool CheckNullableImpl<T>(T? o) where T: struct { return o != null; }
, Anda akan berakhir dengan patokan yang jelas menunjukkan bahwa!=
jauh lebih lambat dibandingkan!=
. Yang seharusnya mengarahkan Anda pada kesimpulan bahwa masalah yang dijawab oleh jawaban Anda bukan tentang!=
vsHasValue
sama sekali.