Diberikan kode berikut:
string someString = null;
switch (someString)
{
case string s:
Console.WriteLine("string s");
break;
case var o:
Console.WriteLine("var o");
break;
default:
Console.WriteLine("default");
break;
}
Mengapa pernyataan sakelar cocok case var o
?
Pemahaman saya case string s
tidak cocok ketika s == null
karena (secara efektif) (null as string) != null
mengevaluasi salah. IntelliSense pada VS Code memberi tahu saya bahwa o
itu string
juga. Ada pemikiran?
Mirip dengan: C # 7 switch case dengan pemeriksaan null
o
inistring
(dikonfirmasi dengan obat generik - yaituFoo(o)
di manaFoo<T>(T template) => typeof(T).Name
) - itu adalah kasus yang sangat menarik di manastring x
berperilaku berbeda darivar x
bahkan ketikax
diketik (oleh kompilator) sebagaistring
var
dalam konteks ini sama sekali. Itu sepertinya hal yang akan saya temukan di C ++, bukan dalam bahasa yang dimaksudkan untuk mengarahkan programmer "ke lubang kesuksesan". Di sini,var
keduanya ambigu dan tidak berguna, hal-hal yang biasanya ingin dihindari oleh desain C #.switch
bisa tidak dapat diucapkan - tipe anonim, dll; dan itu tidak ambigu - kompilator mengetahui dengan jelas tipenya; hanya membingungkan (setidaknya bagi saya) bahwanull
aturannya sangat berbeda!Jawaban:
Di dalam
switch
pernyataan pencocokan pola yang menggunakan acase
untuk tipe eksplisit menanyakan apakah nilai yang dimaksud adalah dari tipe spesifik itu, atau tipe turunan. Ini sama persis denganis
switch (someString) { case string s: } if (someString is string)
Nilai
null
tidak memiliki tipe dan karenanya tidak memenuhi salah satu kondisi di atas. Jenis statissomeString
tidak ikut bermain di kedua contoh.The
var
Tipe meskipun dalam pencocokan pola bertindak sebagai kartu liar dan akan cocok dengan nilai apapun termasuknull
.The
default
terjadi di sini adalah kode mati. Thecase var o
akan ditemukan nilai, null atau non-null. Kasus non-default selalu menang atas kasus default sehinggadefault
tidak akan pernah terkena. Jika Anda melihat IL Anda akan melihat itu bahkan tidak dipancarkan.Sekilas mungkin tampak aneh bahwa kompilasi ini tanpa peringatan apa pun (pasti membuat saya bingung). Tapi ini cocok dengan perilaku C # yang kembali ke 1.0. Kompilator mengizinkan
default
kasus bahkan ketika ia dapat dengan mudah membuktikan bahwa ia tidak akan pernah terpukul. Perhatikan sebagai contoh berikut ini:bool b = ...; switch (b) { case true: ... case false: ... default: ... }
Disini
default
tidak akan pernah terkena (bahkan untukbool
yang memiliki nilai bukan 1 atau 0). Namun C # telah mengizinkan ini sejak 1.0 tanpa peringatan. Pencocokan pola hanya sejalan dengan perilaku ini di sini.sumber
var
menjadi tipestring
ketika sebenarnya tidak (sejujurnya tidak yakin tipe apa yang harus diakui)var
dalam contoh dihitung menjadistring
.csc /stiffUpperLip
null
adalahstring
referensi yang valid , danstring
referensi apa pun (termasuknull
) dapat secara implisit dilemparkan (memelihara referensi) keobject
referensi, danobject
referensi apa pun yangnull
dapat berhasil disebarluaskan (eksplisit) ke jenis lain, masih adanull
. Tidak benar-benar hal yang sama dalam hal sistem tipe kompilator.Saya mengumpulkan beberapa komentar twitter di sini - ini sebenarnya baru bagi saya, dan saya berharap jaredpar akan memberikan jawaban yang lebih komprehensif, tetapi; versi pendek yang saya pahami:
case string s:
ditafsirkan sebagai
if(someString is string) { s = (string)someString; ...
atauif((s = (someString as string)) != null) { ... }
- salah satunya melibatkannull
tes - yang gagal dalam kasus Anda; sebaliknya:case var o:
di mana kompilator menyelesaikan
o
apastring
adanyao = (string)someString; ...
- tidak adanull
pengujian, meskipun faktanya terlihat serupa di permukaan, hanya dengan kompilator yang menyediakan tipenya.akhirnya:
default:
di sini tidak dapat dihubungi , karena kasus di atas mencakup semuanya. Ini mungkin bug kompilator karena tidak mengeluarkan peringatan kode yang tidak dapat dijangkau.
Saya setuju bahwa ini sangat halus dan bernuansa, dan membingungkan. Namun ternyata
case var o
skenario tersebut digunakan dengan propagasi null (o?.Length ?? 0
dll). Saya setuju bahwa aneh bahwa ini bekerja sangat berbeda antaravar o
danstring s
, tetapi itulah yang dilakukan kompilator saat ini.sumber
Itu karena
case <Type>
cocok pada jenis dinamis (waktu proses), bukan jenis statis (waktu kompilasi).null
tidak memiliki tipe dinamis, jadi tidak bisa ditandingistring
.var
hanyalah fallback.(Memposting karena saya suka jawaban singkat.)
sumber