Mengapa itu Valid untuk Menggabungkan Null Strings tetapi tidak untuk Memanggil "null.ToString ()"?


126

Ini adalah kode C # yang valid

var bob = "abc" + null + null + null + "123";  // abc123

Ini bukan kode C # yang valid

var wtf = null.ToString(); // compiler error

Mengapa pernyataan pertama itu valid?


97
Saya merasa aneh bahwa Anda null.ToString()diberi nama wtf. Mengapa itu mengejutkan Anda? Anda tidak dapat memanggil metode contoh saat Anda tidak memiliki alasan untuk memanggilnya.
BoltClock

11
@BoltClock: Tentu saja mungkin memanggil metode instance pada instance nol Hanya tidak mungkin dalam C #, tetapi sangat valid pada CLR :)
leppie

1
Jawaban yang berkaitan dengan String.Compat hampir benar. Bahkan, contoh spesifik dalam pertanyaan adalah salah satu pelipatan konstan , dan nol di baris pertama dihilangkan oleh kompiler - yaitu mereka tidak pernah dievaluasi saat runtime karena mereka tidak ada lagi - kompiler telah menghapusnya. Saya menulis sedikit monolog tentang semua aturan untuk penggabungan dan pelipatan konstan dari String di sini untuk info lebih lanjut: stackoverflow.com/questions/9132338/… .
Chris Shain

77
Anda dapat menambahkan apa pun ke string tetapi Anda tidak dapat membuat string dari ketiadaan.
RGB

Apakah pernyataan kedua tidak valid? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
ctrl-alt-delor

Jawaban:


163

Alasan yang pertama bekerja:

Dari MSDN :

Dalam operasi penggabungan string, kompiler C # memperlakukan string null sama dengan string kosong, tetapi tidak mengonversi nilai string null asli.

Informasi lebih lanjut tentang + operator biner :

Operator biner + melakukan penggabungan string ketika satu atau kedua operan bertipe string.

Jika operan penggabungan string adalah null, string kosong diganti. Jika tidak, argumen non-string apa pun akan dikonversi ke representasi string dengan memanggil ToStringmetode virtual yang diwarisi dari objek tipe.

Jika ToStringkembali null, string kosong diganti.

Alasan kesalahan di detik adalah:

null (C # Referensi) - Kata kunci nol adalah literal yang mewakili referensi nol, yang tidak merujuk ke objek apa pun. null adalah nilai default variabel tipe referensi.


1
Apakah ini akan berhasil? var wtf = ((String)null).ToString();Saya bekerja di Jawa baru-baru ini di mana casting null's mungkin, sudah lama sejak saya bekerja dengan C #.
Jochem

14
@Jochem: Anda masih mencoba memanggil metode pada objek nol, jadi saya kira tidak. Anggap saja sebagai null.ToString()vs ToString(null).
Svish

@Vish ya, sekarang saya pikirkan lagi, itu adalah objek nol, jadi Anda benar, itu tidak akan berfungsi. Ini tidak akan di Jawa juga: pengecualian pointer nol. Lupakan. Tnx untuk balasan Anda! [sunting: mengujinya di Java: NullPointerException. Dengan perbedaan yang dikompilasi oleh cast, tanpa cast tidak].
Jochem

umumnya tidak ada alasan untuk sengaja melakukan concat atau ToString kata kunci null. Jika Anda membutuhkan string kosong gunakan string.Empty. jika Anda perlu memeriksa apakah variabel string adalah nol, Anda dapat menggunakan (myString == null) atau string.IsNullOrEmpty (myString). Atau untuk mengubah variabel string nol menjadi string.Empty gunakan myNewString = (myString == null ?? string.Empty)
csauve

@Jochem casting itu akan membuatnya dikompilasi tetapi memang akan melempar NullReferenceException saat runtime
jeroenh

108

Karena +operator di C # diterjemahkan secara internal String.Concat, yang merupakan metode statis. Dan metode ini terjadi untuk memperlakukan nullseperti string kosong. Jika Anda melihat sumber String.Concatdi Reflector, Anda akan melihatnya:

// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array

(MSDN menyebutkannya juga: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )

Di sisi lain, ToString()apakah metode instance, yang tidak dapat Anda panggil null(jenis apa yang harus digunakan null?).


2
Tidak ada operator + di kelas String .. Jadi apakah kompiler menerjemahkan ke String.Compat?
superlogis

@superlogical Ya, itulah yang dilakukan oleh kompiler. Jadi sebenarnya, +operator pada string dalam C # hanyalah gula sintaksis untuk String.Concat.
Botz3000

Menambah itu: Kompilator secara otomatis mengambil kelebihan dari Concat yang paling masuk akal. Kelebihan yang tersedia adalah 1, 2 atau 3 parameter objek, 4 parameter objek + __arglistdan paramsversi array objek.
Wormbo

Apa array string yang sedang dimodifikasi di sana? Apakah Concatselalu membuat array baru string non-null bahkan ketika diberi array string non-null, atau ada hal lain yang terjadi?
supercat

@supercat Array yang dimodifikasi adalah array baru, yang kemudian diteruskan ke metode pembantu pribadi. Anda dapat melihat kode sendiri menggunakan reflektor.
Botz3000

29

The sampel pertama akan diterjemahkan menjadi:

var bob = String.Concat("abc123", null, null, null, "abs123");

Itu Concat Metode pemeriksaan input dan menerjemahkan null sebagai string kosong

The sampel kedua akan diterjemahkan menjadi:

var wtf = ((object)null).ToString();

Jadi nullpengecualian referensi akan dihasilkan di sini


Sebenarnya, AccessViolationExceptionakan dilempar :)
leppie

Saya baru saja :) ((object)null).ToString()=> AccessViolation ((object)1 as string).ToString()=>NullReference
leppie

1
Saya sudah mendapat NullReferenceException. DN 4.0
Viacheslav Smityukh

Menarik. Ketika saya memasukkan ke ((object)null).ToString()dalam try/catchsaya NullReferenceExceptionjuga mendapatkan .
leppie

3
@Ippie kecuali yang tidak membuang AccessViolation (mengapa?) - NullReferenceException di sini.
jeroenh

11

Bagian pertama dari kode Anda diperlakukan seperti itu di String.Concat,

yang disebut oleh kompilator C # saat Anda menambahkan string. " abc" + nullditerjemahkan ke String.Concat("abc", null),

dan secara internal, metode itu diganti nulldengan String.Empty. Jadi, itu sebabnya bagian pertama kode Anda tidak membuang pengecualian. itu seperti

var bob = "abc" + string.Empty + string.Empty + string.Empty + "123";  //abc123

Dan di bagian ke-2 dari kode Anda melemparkan pengecualian karena 'nol' bukan objek, kata kunci nol adalah literal yang mewakili referensi nol , yang tidak merujuk ke objek apa pun. null adalah nilai default variabel tipe referensi.

Dan ' ToString()' adalah metode yang dapat dipanggil oleh instance dari suatu objek tetapi tidak secara literal.


3
String.Emptytidak sama dengan null. Itu hanya diperlakukan dengan cara yang sama dalam beberapa metode seperti String.Concat. Misalnya, jika Anda memiliki variabel string diatur ke null, C # tidak akan menggantinya dengan String.Emptyjika Anda mencoba memanggil metode di dalamnya.
Botz3000

3
Hampir. nulltidak diperlakukan seperti String.Emptyoleh C #, itu hanya diperlakukan seperti itu di String.Concat, yang adalah apa yang disebut kompiler C # ketika Anda menambahkan string. "abc" + nullditerjemahkan ke String.Concat("abc", null), dan secara internal, metode itu diganti nulldengan String.Empty. Bagian kedua sepenuhnya benar.
Botz3000

9

Dalam kerangka COM yang mendahului. Net, itu perlu untuk setiap rutin yang menerima string untuk membebaskannya ketika sudah selesai dengan itu. Karena itu sangat umum untuk string kosong untuk masuk dan keluar dari rutinitas, dan karena berusaha untuk "membebaskan" pointer nol didefinisikan sebagai operasi tidak melakukan apa-apa yang sah, Microsoft memutuskan untuk memiliki string pointer kosong mewakili string kosong.

Untuk memungkinkan kompatibilitas dengan COM, banyak rutin di .net akan menafsirkan objek nol sebagai representasi hukum sebagai string kosong. Dengan beberapa perubahan kecil .net dan bahasanya (yang paling memungkinkan anggota contoh untuk menunjukkan "jangan dipanggil sebagai virtual"), Microsoft dapat membuat nullobjek dengan tipe String yang dinyatakan berperilaku lebih seperti string kosong. Jika Microsoft telah melakukan itu, itu juga harus membuat Nullable<T>pekerjaan agak berbeda (sehingga memungkinkan - Nullable<String>sesuatu yang seharusnya mereka lakukan IMHO) dan / atau menentukan NullableStringjenis yang sebagian besar akan dipertukarkan dengan String, tetapi yang tidak akan menganggap nullsebagai string kosong yang valid.

Seperti adanya, ada beberapa konteks di mana a nullakan dianggap sebagai string kosong yang sah dan yang lainnya tidak. Bukan situasi yang sangat membantu, tetapi yang harus diperhatikan oleh programmer. Secara umum, ekspresi formulir stringValue.someMemberakan gagal jika stringValueada null, tetapi sebagian besar metode kerangka kerja dan operator yang menerima string sebagai parameter akan dianggap nullsebagai string kosong.


5

'+'adalah operator infiks. Seperti halnya operator apa pun, itu benar-benar memanggil metode. Anda dapat membayangkan versi non-infiks"wow".Plus(null) == "wow"

Pelaksana telah memutuskan sesuatu seperti ini ...

class String
{
  ...
  String Plus(ending)
  {
     if(ending == null) return this;
     ...
  }
} 

Jadi .. teladan Anda menjadi

var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123");  // abc123

yang sama dengan

var bob = "abc".Plus("123");  // abc123

Tanpa titik tidak null menjadi string. Jadi null.ToString()tidak ada bedanya null.VoteMyAnswer(). ;)


Sungguh, ini lebih seperti var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. Kelebihan operator adalah metode statis di hati mereka: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Jika tidak, var bob = null + "abc";atau khususnya string bob = null + null;tidak akan valid.
Ben Mosher

Anda benar, saya hanya merasa saya akan terlalu membingungkan jika saya menjelaskannya seperti itu.
Nigel Thorne

3

Saya kira karena itu literal yang tidak merujuk ke objek apa pun. ToString()membutuhkan sebuah object.


3

Seseorang berkata di utas diskusi ini bahwa Anda tidak dapat membuat string dari ketiadaan. (yang merupakan ungkapan yang bagus seperti yang saya pikirkan). Tapi ya - Anda dapat :-), seperti yang ditunjukkan contoh berikut:

var x = null + (string)null;     
var wtf = x.ToString();

berfungsi dengan baik dan tidak membuang pengecualian sama sekali. Satu-satunya perbedaan adalah bahwa Anda perlu membuang salah satu nulls ke dalam string - jika Anda menghapus cast (string) , maka contohnya masih mengkompilasi, tetapi melempar pengecualian run-time: "Operator '+' ambigu pada operan dari ketik '<null>' dan '<null>' ".

NB Dalam contoh kode di atas, nilai x tidak nol seperti yang Anda harapkan, itu sebenarnya adalah string kosong setelah Anda memasukkan salah satu operan ke dalam string.


Fakta lain yang menarik adalah bahwa dalam C # /. NET cara nulldiperlakukan tidak selalu sama jika Anda menganggap tipe data yang berbeda. Sebagai contoh:

int? x = 1;  //  string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());

Mengenai baris pertama dari cuplikan kode: If xadalah variabel integer yang dapat dibatalkan (misint? ) yang berisi nilai 1, maka Anda mendapatkan hasilnya <null>kembali. Jika itu adalah string (seperti yang ditunjukkan dalam komentar) dengan nilai "1", maka Anda akan "1"kembali daripada <null>.

NB Juga menarik: Jika Anda menggunakan var x = 1;untuk baris pertama, maka Anda mendapatkan kesalahan runtime. Mengapa? Karena tugas akan mengubah variabel xmenjadi tipe data int, yang tidak dapat dibatalkan. Compiler tidak berasumsi di int?sini, dan karenanya gagal di baris ke-2 di mananull ditambahkan.


2

Menambahkan nullke string diabaikan saja. null(dalam contoh kedua Anda) bukan turunan dari objek apa pun, jadi ia bahkan tidak memiliki ToString()metode. Itu hanya literal.


1

Karena tidak ada perbedaan antara string.Emptydan nullketika Anda memainkan string. Anda dapat melewatkan null string.Formatjuga. Tetapi Anda mencoba memanggil metode null, yang akan selalu menghasilkan a NullReferenceExceptiondan karenanya menghasilkan kesalahan kompiler.
Jika karena alasan tertentu Anda benar-benar ingin melakukannya, Anda dapat menulis metode ekstensi, yang memeriksa nulldan kemudian kembali string.Empty. Tetapi ekstensi seperti itu seharusnya hanya digunakan jika benar-benar diperlukan (menurut saya).


0

Secara umum: Ini mungkin atau mungkin tidak valid menerima null sebagai parameter tergantung pada spesifikasi, tetapi selalu tidak valid untuk memanggil metode pada null.


Itu dan topik lain mengapa operan + operator bisa nol jika ada string. Ini adalah hal yang agak VB (maaf guys) untuk membuat hidup programmer lebih mudah, atau seandainya programmer tidak dapat menangani nulls. Saya sepenuhnya tidak setuju dengan spesifikasi ini. 'tidak diketahui' + 'apapun' harus tetap 'tidak diketahui' ...

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.