Karena true
bukan tipe string, bagaimana null + true
string itu?
string s = true; //Cannot implicitly convert type 'bool' to 'string'
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
apa alasan dibalik ini?
Karena true
bukan tipe string, bagaimana null + true
string itu?
string s = true; //Cannot implicitly convert type 'bool' to 'string'
bool b = null + true; //Cannot implicitly convert type 'string' to 'bool'
apa alasan dibalik ini?
Jawaban:
Anehnya, ini hanya mengikuti aturan dari spesifikasi bahasa C #.
Dari bagian 7.3.4:
Operasi dalam bentuk x op y, di mana op adalah operator biner yang dapat kelebihan beban, x adalah ekspresi tipe X, dan y adalah ekspresi tipe Y, diproses sebagai berikut:
- Himpunan calon operator yang ditentukan pengguna yang disediakan oleh X dan Y untuk operator operasi op (x, y) ditentukan. Himpunan ini terdiri dari gabungan operator kandidat yang disediakan oleh X dan operator kandidat yang disediakan oleh Y, masing-masing ditentukan menggunakan aturan §7.3.5. Jika X dan Y adalah tipe yang sama, atau jika X dan Y diturunkan dari tipe basis yang sama, maka operator kandidat bersama hanya terjadi dalam kumpulan gabungan satu kali.
- Jika kumpulan calon operator yang ditentukan pengguna tidak kosong, maka ini menjadi kumpulan calon operator untuk operasi. Jika tidak, implementasi op operator biner yang telah ditentukan, termasuk bentuk yang diangkat, menjadi kumpulan calon operator untuk operasi tersebut. Implementasi yang telah ditentukan sebelumnya dari operator tertentu ditentukan dalam deskripsi operator (§7.8 hingga §7.12).
- Aturan resolusi kelebihan beban pada §7.5.3 diterapkan ke kumpulan operator kandidat untuk memilih operator terbaik sehubungan dengan daftar argumen (x, y), dan operator ini menjadi hasil dari proses resolusi kelebihan beban. Jika resolusi kelebihan beban gagal memilih satu operator terbaik, kesalahan waktu pengikatan terjadi.
Jadi, mari kita bahas ini secara bergantian.
X adalah tipe nol di sini - atau bukan tipe sama sekali, jika Anda ingin menganggapnya seperti itu. Itu tidak memberikan kandidat apa pun. Y adalah bool
, yang tidak menyediakan +
operator yang ditentukan pengguna . Jadi langkah pertama tidak menemukan operator yang ditentukan pengguna.
Kompiler kemudian beralih ke poin poin kedua, melihat melalui implementasi + operator biner yang telah ditentukan dan formulir yang diangkat. Ini tercantum di bagian 7.8.4 spesifikasi.
Jika Anda melihat melalui operator yang telah ditentukan sebelumnya, satu - satunya yang berlaku adalah string operator +(string x, object y)
. Jadi set kandidat memiliki satu entri. Itu membuat poin terakhir sangat sederhana ... resolusi kelebihan beban memilih operator itu, memberikan tipe ekspresi keseluruhan string
.
Satu hal yang menarik adalah hal ini akan terjadi meskipun ada operator yang ditentukan pengguna lain yang tersedia pada jenis yang tidak disebutkan. Sebagai contoh:
// Foo defined Foo operator+(Foo foo, bool b)
Foo f = null;
Foo g = f + true;
Tidak apa-apa, tetapi tidak digunakan untuk literal nol, karena kompilator tidak tahu untuk mencarinya Foo
. Itu hanya tahu untuk dipertimbangkan string
karena ini adalah operator yang ditentukan sebelumnya secara eksplisit tercantum dalam spesifikasi. (Sebenarnya, ini bukan operator yang ditentukan oleh tipe string ... 1 ) Itu berarti bahwa ini akan gagal untuk dikompilasi:
// Error: Cannot implicitly convert type 'string' to 'Foo'
Foo f = null + true;
Jenis operan kedua lainnya akan menggunakan beberapa operator lain, tentu saja:
var x = null + 0; // x is Nullable<int>
var y = null + 0L; // y is Nullable<long>
var z = null + DayOfWeek.Sunday; // z is Nullable<DayOfWeek>
1 Anda mungkin bertanya - tanya mengapa tidak ada operator + string. Ini pertanyaan yang masuk akal, dan saya hanya menebak-nebak jawabannya, tetapi pertimbangkan ungkapan ini:
string x = a + b + c + d;
Jika string
tidak ada casing khusus di kompiler C #, ini akan berakhir secara efektif:
string tmp0 = (a + b);
string tmp1 = tmp0 + c;
string x = tmp1 + d;
Jadi itu menciptakan dua string perantara yang tidak perlu. Namun, karena ada dukungan khusus di dalam kompilator, ia sebenarnya dapat mengkompilasi di atas sebagai:
string x = string.Concat(a, b, c, d);
yang dapat membuat hanya satu string dengan panjang yang tepat, menyalin semua data tepat satu kali. Bagus.
true
tidak dapat dikonversi ke string
. Jika ekspresi itu valid, jenisnya akan string
, tetapi dalam kasus ini kegagalan untuk mengonversi ke string membuat seluruh ekspresi menjadi error, dan karenanya tidak memiliki tipe.
x
bertipe string
. Perhatikan bahwa tanda tangan yang digunakan di sini adalah string operator+(string, object)
- itu diubah bool
menjadi object
(yang bagus), bukan menjadi string
.
Alasannya adalah karena begitu Anda memperkenalkan +
aturan pengikatan operator C # mulai berlaku. Ini akan mempertimbangkan kumpulan +
operator yang tersedia dan memilih kelebihan beban terbaik. Salah satu operator tersebut adalah sebagai berikut
string operator +(string x, object y)
Kelebihan beban ini kompatibel dengan tipe argumen dalam ekspresi null + true
. Oleh karena itu dipilih sebagai operator dan dievaluasi sebagai dasarnya ((string)null) + true
yang mengevaluasi nilai "True"
.
Bagian 7.7.4 dari spesifikasi bahasa C # berisi rincian seputar resolusi ini.
operator+
untuk string
. Alih-alih itu hanya ada dalam pikiran kompiler dan itu hanya menerjemahkannya menjadi panggilan untukstring.Concat
Kompilator keluar mencari operator + () yang bisa mengambil argumen null terlebih dahulu. Tak satu pun dari tipe nilai standar yang memenuhi syarat, null bukanlah nilai yang valid untuk mereka. Satu-satunya kecocokan adalah System.String.operator + (), tidak ada ambiguitas.
Argumen ke-2 dari operator itu juga berupa string. Itu tidak berguna, tidak bisa secara implisit mengubah bool menjadi string.
Menariknya, menggunakan Reflector untuk memeriksa apa yang dihasilkan, kode berikut:
string b = null + true;
Console.WriteLine(b);
diubah menjadi ini oleh kompilator:
Console.WriteLine(true);
Alasan di balik "pengoptimalan" ini agak aneh yang harus saya katakan, dan tidak sesuai dengan pilihan operator yang saya harapkan.
Juga, kode berikut ini:
var b = null + true;
var sb = new StringBuilder(b);
diubah menjadi
string b = true;
StringBuilder sb = new StringBuilder(b);
dimana string b = true;
sebenarnya tidak diterima oleh kompilator.
null
akan dilemparkan ke string null, dan ada konverter implisit dari bool ke string sehingga true
akan dilemparkan ke string dan kemudian, +
operator akan diterapkan: seperti: string str = "" + true.ToString ();
jika Anda memeriksanya dengan Ildasm:
string str = null + true;
itu seperti di bawah ini:
.locals init ([0] string str)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: box [mscorlib]System.Boolean
IL_0007: call string [mscorlib]System.String::Concat(object)
IL_000c: stloc.0
var b = (null + DateTime.Now); // String
var b = (null + 1); // System.Nullable<Int32> | same with System.Single, System.Double, System.Decimal, System.TimeSpan etc
var b = (null + new Object()); // String | same with any ref type
Gila?? Tidak, pasti ada alasan di baliknya.
Seseorang menelepon Eric Lippert
...
Alasannya adalah kemudahan (merangkai string adalah tugas yang umum).
Seperti yang dikatakan BoltClock, operator '+' didefinisikan pada tipe numerik, string, dan juga dapat didefinisikan untuk tipe kita sendiri (operator overloading).
Jika tidak ada operator '+' yang kelebihan beban pada tipe argumen dan bukan tipe numerik, kompilator defaultnya adalah penggabungan string.
Kompilator menyisipkan panggilan ke String.Concat(...)
saat Anda menggabungkan menggunakan '+', dan implementasi Concat memanggil ToString pada setiap objek yang diteruskan ke dalamnya.