Cukup menjengkelkan untuk menguji semua string saya null
sebelum saya dapat dengan aman menerapkan metode seperti ToUpper()
, StartWith()
dll ...
Jika nilai default string
adalah string kosong, saya tidak perlu menguji, dan saya akan merasa lebih konsisten dengan tipe nilai lainnya seperti int
atau double
misalnya. Selain itu Nullable<String>
akan masuk akal.
Jadi mengapa para desainer C # memilih untuk menggunakan null
sebagai nilai default dari string?
Catatan: Ini berkaitan dengan pertanyaan ini , tetapi lebih fokus pada mengapa dan bukan apa yang harus dilakukan dengannya.
c#
string
default-value
Marcel
sumber
sumber
null
(dan juga saya sarankan Anda memperlakukannull
dan mengosongkan string secara konseptual sebagai hal yang berbeda). Nilai nol bisa merupakan hasil dari kesalahan di suatu tempat, sementara string kosong harus menyampaikan arti yang berbeda.Jawaban:
Karena
string
adalah tipe referensi dan nilai default untuk semua tipe referensi adalahnull
.Itu konsisten dengan perilaku tipe referensi. Sebelum memohon anggota contoh mereka, seseorang harus meletakkan cek di tempat untuk referensi nol.
Menetapkan nilai default ke jenis referensi tertentu selain
null
akan membuatnya tidak konsisten .Nullable<T>
bekerja dengan tipe nilai. Yang perlu diperhatikan adalah fakta yangNullable
tidak diperkenalkan pada platform .NET asli sehingga akan ada banyak kode yang rusak seandainya mereka mengubah aturan itu. ( Courtesy @jcolebrand )sumber
String
, kecuali untuk (1) perilaku nilai jenis-ish-memiliki nilai yang dapat digunakan default, dan (2) tambahan lapisan disayangkan tipuan tinju waktu itu dilemparkan keObject
. Mengingat bahwa penumpukan tumpukanstring
adalah unik, memiliki perawatan khusus untuk menghindari tinju tambahan tidak akan terlalu banyak (sebenarnya, mampu menentukan perilaku tinju non-standar akan menjadi hal yang baik untuk jenis lain juga).Habib benar - karena
string
merupakan jenis referensi.Tetapi yang lebih penting, Anda tidak perlu memeriksa
null
setiap kali Anda menggunakannya. Anda mungkin harus melemparArgumentNullException
jika seseorang melewati fungsi Anda sebagainull
referensi.Begini masalahnya - kerangka kerja akan melempar
NullReferenceException
untuk Anda jika Anda mencoba memanggil.ToUpper()
string. Ingatlah bahwa kasus ini masih dapat terjadi bahkan jika Anda menguji argumen Andanull
karena properti atau metode apa pun pada objek yang diteruskan ke fungsi Anda sebagai parameter dapat dievaluasinull
.Yang sedang berkata, memeriksa string kosong atau nol adalah hal yang umum dilakukan, sehingga mereka menyediakan
String.IsNullOrEmpty()
danString.IsNullOrWhiteSpace()
hanya untuk tujuan ini.sumber
NullReferenceException
diri Anda sendiri ( msdn.microsoft.com/en-us/library/ms173163.aspx ); Anda melemparArgumentNullException
jika metode Anda tidak dapat menerima referensi kosong. Juga, NullRef biasanya merupakan salah satu pengecualian yang lebih sulit untuk diagnosa ketika Anda memperbaiki masalah, jadi saya tidak berpikir rekomendasi untuk tidak memeriksa null adalah yang sangat bagus.ArgumentNullException
memiliki manfaat tambahan karena bisa memberikan nama parameter. Selama debugging, ini menghemat ... err, detik. Tapi detik-detik penting.Anda dapat menulis metode ekstensi (sesuai nilainya):
Sekarang ini bekerja dengan aman:
sumber
.EmptyNull()
, mengapa tidak menggunakan(str ?? "")
saja di tempat yang dibutuhkan? Yang mengatakan, saya setuju dengan sentimen yang diungkapkan dalam komentar @ DaveMarkle: Anda mungkin tidak boleh.null
danString.Empty
secara konsep berbeda, dan Anda tidak dapat memperlakukan satu sama seperti yang lainnya.Anda juga dapat menggunakan yang berikut ini, pada C # 6.0
Hasil string akan menjadi nol.
sumber
public string Name { get; set; } = string.Empty;
String kosong dan null pada dasarnya berbeda. Null adalah tidak adanya nilai dan string kosong adalah nilai yang kosong.
Bahasa pemrograman membuat asumsi tentang "nilai" suatu variabel, dalam hal ini string kosong, akan sama baiknya dengan menginisiasi string dengan nilai lain yang tidak akan menyebabkan masalah referensi nol.
Juga, jika Anda meneruskan pegangan ke variabel string itu ke bagian lain dari aplikasi, maka kode itu tidak akan memiliki cara untuk memvalidasi apakah Anda sengaja memberikan nilai kosong atau Anda lupa mengisi nilai variabel itu.
Kesempatan lain di mana ini akan menjadi masalah adalah ketika string adalah nilai balik dari beberapa fungsi. Karena string adalah tipe referensi dan secara teknis dapat memiliki nilai sebagai nol dan kosong keduanya, maka fungsi tersebut juga secara teknis dapat mengembalikan nol atau kosong (tidak ada yang menghentikannya untuk melakukannya). Sekarang, karena ada 2 gagasan tentang "tidak adanya nilai", yaitu string kosong dan null, semua kode yang menggunakan fungsi ini harus melakukan 2 pemeriksaan. Satu untuk kosong dan yang lainnya untuk nol.
Singkatnya, selalu baik untuk hanya memiliki 1 representasi untuk satu negara. Untuk diskusi yang lebih luas tentang kosong dan kosong, lihat tautan di bawah ini.
/software/32578/sql-empty-string-vs-null-value
NULL vs Kosong saat berurusan dengan input pengguna
sumber
null
untuk mewakili string kosong. Ada beberapa cara .net dapat menerapkan semantik serupa, seandainya mereka memilih untuk melakukannya, terutama mengingat bahwaString
memiliki sejumlah karakteristik yang menjadikannya tipe yang unik [misalnya dan dua tipe array adalah satu-satunya jenis yang alokasi ukuran tidak konstan].Alasan / masalah mendasar adalah bahwa perancang spesifikasi CLS (yang mendefinisikan bagaimana bahasa berinteraksi dengan .net) tidak mendefinisikan sarana yang oleh anggota kelas dapat menentukan bahwa mereka harus dipanggil secara langsung, bukan melalui
callvirt
, tanpa penelepon melakukan suatu cek referensi-nol; juga tidak memberikan banyak definisi struktur yang tidak akan dikenakan tinju "normal".Jika spesifikasi CLS mendefinisikan cara seperti itu, maka akan mungkin bagi .net untuk secara konsisten mengikuti petunjuk yang ditetapkan oleh Common Object Model (COM), di mana referensi string nol dianggap secara semantik setara dengan string kosong, dan untuk lainnya tipe kelas yang tidak dapat diubah yang ditentukan pengguna yang seharusnya memiliki semantik nilai untuk juga mendefinisikan nilai default. Pada dasarnya, apa yang akan terjadi bagi masing-masing anggota
String
, misalnyaLength
ditulis sebagai sesuatu seperti[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Pendekatan ini akan menawarkan semantik yang sangat bagus untuk hal-hal yang harus berperilaku seperti nilai, tetapi karena masalah implementasi perlu disimpan di heap. Kesulitan terbesar dengan pendekatan ini adalah bahwa semantik konversi antara jenis danObject
bisa menjadi sedikit keruh.Suatu pendekatan alternatif akan memungkinkan definisi tipe struktur khusus yang tidak diwarisi dari
Object
tetapi memiliki operasi tinju kustom dan unboxing (yang akan dikonversi ke / dari beberapa jenis kelas lainnya). Di bawah pendekatan seperti itu, akan ada tipe kelasNullableString
yang berperilaku sebagai string tidak sekarang, dan tipe struct kotak-kustomString
, yang akan menampung bidangValue
tipe privat tunggalString
. Mencoba mengonversikanString
keNullableString
atauObject
akan kembaliValue
jika bukan nol, atauString.Empty
jika nol. Mencoba melakukan castString
, referensi non-nol keNullableString
instance akan menyimpan referensi diValue
(mungkin menyimpan null jika panjangnya nol); casting referensi lain akan menimbulkan pengecualian.Meskipun string harus disimpan di heap, secara konseptual tidak ada alasan mengapa mereka tidak boleh berperilaku seperti tipe nilai yang memiliki nilai default non-nol. Memiliki mereka disimpan sebagai struktur "normal" yang memegang referensi akan lebih efisien untuk kode yang menggunakannya sebagai tipe "string", tetapi akan menambahkan lapisan tipuan dan inefisiensi tambahan saat casting ke "objek". Meskipun saya tidak melihat .net menambahkan salah satu dari fitur di atas pada akhir ini, mungkin desainer kerangka masa depan mungkin mempertimbangkan untuk memasukkannya.
sumber
Nullable<>
, string dapat diimplementasikan kembali sebagai tipe nilai; Saya tidak dapat berbicara mengenai biaya dan manfaat dari pilihan semacam itu.string
lebih efisien daripada yangNullable<string>
seharusnya, harus menggunakan metode "lebih efisien" lebih memberatkan daripada mampu menggunakan pendekatan yang sama untuk semua nilai basis data data yang dapat dibatalkan.Karena variabel string adalah referensi , bukan instance .
Inisialisasi ke Empty secara default mungkin saja tetapi akan memperkenalkan banyak inkonsistensi di seluruh papan.
sumber
string
untuk menjadi tipe referensi. Yang pasti, karakter aktual yang membentuk string tentu saja harus disimpan di heap, tetapi mengingat jumlah dukungan khusus yang dimiliki string di CLR, tidak akan sulit untukSystem.String
menjadi tipe nilai dengan bidangValue
tipe tunggal pribadiHeapString
. Bidang itu akan menjadi tipe referensi, dan akan default untuknull
, tetapiString
struct yangValue
bidangnya nol akan berperilaku sebagai string kosong. Satu-satunya kelemahan dari pendekatan ini adalah ...String
keObject
, tanpa adanya kode kasus khusus dalam runtime, menyebabkan pembuatanString
instance kotak pada heap, daripada hanya menyalin referensi keHeapString
..Length
dll. Sehingga instance yang menyimpan referensi nol tidak akan mencoba untuk menghindarinya tetapi sebaliknya berperilaku sesuai untuk string kosong. Apakah Kerangka akan lebih baik atau lebih buruk denganstring
diimplementasikan seperti itu, jika seseorang ingindefault(string)
menjadi string kosong ...string
pembungkus tipe nilai pada bidang tipe referensi akan menjadi pendekatan yang memerlukan perubahan paling sedikit ke bagian lain dari .net [memang, jika seseorang bersedia menerima konversi dariString
untukObject
membuat item kotak tambahan, seseorang bisa sajaString
menjadi struct biasa dengan bidang tipeChar[]
yang tidak pernah terpapar]. Saya pikir memilikiHeapString
tipe mungkin akan lebih baik, tetapi dalam beberapa hal memegang tipe-nilai stringChar[]
akan lebih sederhana.Karena string adalah tipe referensi, tipe referensi adalah nilai defaultnya
null
. Variabel tipe referensi menyimpan referensi ke data aktual.Mari kita gunakan
default
kata kunci untuk kasus ini;str
adalahstring
, jadi itu adalah tipe referensi , jadi nilai default adalahnull
.str
adalahint
, jadi itu adalah tipe nilai , jadi nilai default adalahzero
.sumber
Salah! Mengubah nilai default tidak mengubah fakta bahwa itu adalah tipe referensi dan seseorang masih dapat secara eksplisit mengatur referensi menjadi
null
.Titik benar. Akan lebih masuk akal untuk tidak mengizinkan
null
jenis referensi apa pun, alih-alih memerlukanNullable<TheRefType>
fitur itu.Konsistensi dengan jenis referensi lain. Sekarang, mengapa mengizinkan
null
tipe referensi sama sekali? Mungkin sehingga terasa seperti C, meskipun ini adalah keputusan desain yang dipertanyakan dalam bahasa yang juga menyediakanNullable
.sumber
Mungkin jika Anda akan menggunakan
??
operator saat menetapkan variabel string Anda, ini mungkin membantu Anda.sumber
String adalah objek abadi yang berarti ketika diberi nilai, nilai lama tidak dihapus dari memori, tetapi tetap berada di lokasi lama, dan nilai baru diletakkan di lokasi baru. Jadi jika nilai defaultnya
String a
adalahString.Empty
, itu akan membuang - buangString.Empty
blok dalam memori ketika diberi nilai pertama.Meskipun tampaknya sangat kecil, itu bisa berubah menjadi masalah ketika menginisialisasi sejumlah besar string dengan nilai default
String.Empty
. Tentu saja, Anda selalu bisa menggunakanStringBuilder
kelas yang bisa berubah jika ini akan menjadi masalah.sumber
String.Empty
. Apakah saya salah?string
menjadi string kosong adalah dengan mengizinkan semua-bit-nol sebagai representasi dari string kosong. Ada beberapa cara ini bisa dilakukan, tetapi saya tidak berpikir ada melibatkan inisialisasi referensiString.Empty
.String.Empty
atau""
.string
lokasi penyimpanan akan diperlukan juga mengubah perilaku inisialisasi semua struct atau kelas yang memiliki bidang tipestring
. Itu akan mewakili perubahan yang cukup besar dalam desain .net, yang saat ini mengharapkan untuk menginisialisasi-nol jenis apa pun tanpa harus memikirkan apa itu, simpan hanya untuk ukuran totalnya.Karena string adalah tipe referensi dan nilai default untuk tipe referensi adalah nol.
sumber
Mungkin
string
kata kunci membingungkan Anda, karena terlihat persis seperti pernyataan tipe nilai lainnya , tetapi sebenarnya merupakan alias untukSystem.String
seperti yang dijelaskan dalam pertanyaan ini .Juga warna biru gelap di Visual Studio dan huruf kecil pertama mungkin menyesatkan untuk berpikir itu adalah
struct
.sumber
object
kata kunci? Meskipun diakui, itu jauh lebih sedikit digunakan daripadastring
.int
adalah alias untukSystem.Int32
. Apa maksudmu :)System.Int32
adalahStruct
sehingga memiliki nilai default sementaraSystem.String
adalahClass
memiliki pointer dengan nilai defaultnull
. Mereka disajikan secara visual dalam font / warna yang sama. Tanpa pengetahuan, orang bisa berpikir mereka bertindak dengan cara yang sama (= memiliki nilai default). Jawaban saya ditulis dengan en.wikipedia.org/wiki/Cognitive_psychology ide psikologi kognitif di belakangnya :-)Jenis nullable tidak masuk sampai 2.0.
Jika jenis nullable telah dibuat di awal bahasa maka string tidak akan nullable dan string? akan dibatalkan. Tetapi mereka tidak bisa melakukan kompatibilitas mundur ini.
Banyak orang berbicara tentang tipe-ref atau bukan tipe ref, tetapi string adalah kelas yang tidak biasa dan solusi telah ditemukan untuk membuatnya mungkin.
sumber