Di blog pengembangan, contoh kode online, dan (baru-baru ini) bahkan sebuah buku, saya terus tersandung tentang kode seperti ini:
var y = x as T;
y.SomeMethod();
atau, lebih buruk lagi:
(x as T).SomeMethod();
Itu tidak masuk akal bagi saya. Jika Anda yakin bahwa x
adalah tipe T
, Anda harus menggunakan cor langsung: (T)x
. Jika Anda tidak yakin, Anda dapat menggunakan as
tetapi perlu memeriksa null
sebelum melakukan beberapa operasi. Semua yang dilakukan oleh kode di atas adalah mengubah (berguna) InvalidCastException
menjadi (tidak berguna) NullReferenceException
.
Apakah saya satu-satunya yang berpikir bahwa ini merupakan penyalahgunaan as
kata kunci? Atau apakah saya melewatkan sesuatu yang jelas dan pola di atas benar-benar masuk akal?
c#
casting
type-conversion
Heinzi
sumber
sumber
((T)x).SomeMethod()
, bukan? ;) (hanya bercanda, tentu saja Anda benar!)(f as T).SomeMethod()
Jawaban:
Pemahaman Anda benar. Kedengarannya seperti mencoba mengoptimalkan mikro untuk saya. Anda harus menggunakan gips normal ketika Anda yakin akan tipenya. Selain menghasilkan pengecualian yang lebih masuk akal, itu juga gagal cepat. Jika Anda salah tentang asumsi Anda tentang jenis ini, program Anda akan segera gagal dan Anda akan dapat melihat penyebab kegagalan dengan segera daripada menunggu untuk
NullReferenceException
atauArgumentNullException
atau bahkan kesalahan logis di masa depan. Secara umum,as
ekspresi yang tidak diikuti olehnull
cek di suatu tempat adalah bau kode.Di sisi lain, jika Anda tidak yakin tentang gips dan mengharapkannya gagal, Anda harus menggunakan
as
gips biasa yang dibungkus dengantry-catch
blok. Selain itu, penggunaanas
direkomendasikan atas cek tipe diikuti oleh pemain. Dari pada:yang menghasilkan
isinst
instruksi untukis
kata kunci, dancastclass
instruksi untuk para pemain (secara efektif melakukan pemeran dua kali), Anda harus menggunakan:Ini hanya menghasilkan
isinst
instruksi. Metode sebelumnya memiliki cacat potensial dalam aplikasi multithreaded karena kondisi balapan dapat menyebabkan variabel untuk mengubah jenisnya setelahis
cek berhasil dan gagal pada garis gips. Metode terakhir tidak rentan terhadap kesalahan ini.Solusi berikut tidak disarankan untuk digunakan dalam kode produksi. Jika Anda benar-benar membenci konstruksi mendasar seperti itu di C #, Anda dapat mempertimbangkan beralih ke VB atau bahasa lain.
Jika seseorang sangat membenci sintaksis pemeran, ia dapat menulis metode ekstensi untuk meniru pemeran:
dan gunakan sintaksis rapi [?]:
sumber
cache
objek yang mencoba dibatalkan thread lain dengan menyetelnya kenull
. Dalam skenario bebas kunci, hal-hal semacam ini dapat muncul.Object
. Penggunaan metode pada tipe nilai akan menyebabkannya menjadi kotak yang tidak perlu.To
metode di sini, karena hanya mengkonversi lintas hierarki warisan, yang untuk jenis nilai bagaimanapun juga melibatkan tinju. Tentu saja, seluruh gagasan lebih teoretis daripada serius.IMHO,
as
masuk akal bila dikombinasikan dengannull
cek:sumber
Menggunakan 'sebagai' tidak menerapkan konversi yang ditentukan pengguna sementara para pemain akan menggunakannya jika perlu. Itu bisa menjadi perbedaan penting dalam beberapa kasus.
sumber
Saya menulis sedikit tentang ini di sini:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
Saya mengerti maksud Anda. Dan saya setuju dengan dorongan itu: bahwa operator transmisi berkomunikasi "Saya yakin bahwa objek ini dapat dikonversi ke tipe itu, dan saya bersedia mengambil risiko pengecualian jika saya salah", sedangkan operator "sebagai" berkomunikasi "Saya tidak yakin objek ini dapat dikonversi ke tipe itu; beri saya nol jika saya salah".
Namun, ada perbedaan yang halus. (x sebagai T) .Apa pun yang dikomunikasikan "Saya tidak hanya tahu bahwa x dapat dikonversi ke T, tetapi lebih dari itu, melakukan itu hanya melibatkan konversi referensi atau unboxing, dan lebih jauh lagi, bahwa x bukan nol". Itu memang mengomunikasikan informasi yang berbeda dari ((T) x). Apa pun (), dan mungkin itulah yang dimaksudkan oleh pembuat kode.
sumber
((T)x).Whatever()
juga berkomunikasi yangx
tidak [dimaksudkan sebagai] nol, dan saya sangat meragukan bahwa seorang penulis biasanya akan peduli apakah konversi hanya akanT
terjadi dengan konversi referensi atau unboxing, atau jika itu memerlukan konversi yang ditentukan pengguna atau yang mengubah representasi. Lagi pula, jika saya mendefinisikanpublic static explicit operator Foo(Bar b){}
, maka jelas maksud saya yangBar
dianggap kompatibelFoo
. Jarang saya ingin menghindari konversi ini.Saya sering melihat referensi ke artikel yang menyesatkan ini sebagai bukti bahwa "sebagai" lebih cepat daripada casting.
Salah satu aspek menyesatkan yang lebih jelas dari artikel ini adalah grafik, yang tidak menunjukkan apa yang sedang diukur: Saya menduga itu mengukur gips gagal (di mana "as" jelas jauh lebih cepat karena tidak ada pengecualian dilemparkan).
Jika Anda meluangkan waktu untuk melakukan pengukuran, maka Anda akan melihat bahwa casting, seperti yang Anda harapkan, lebih cepat dari "sebagai" ketika para pemain berhasil.
Saya menduga ini mungkin menjadi salah satu alasan penggunaan "pemujaan kargo" sebagai kata kunci alih-alih pemain.
sumber
Para pemeran langsung membutuhkan sepasang tanda kurung lebih dari
as
kata kunci. Jadi, bahkan dalam kasus di mana Anda 100% yakin apa jenisnya, itu mengurangi kekacauan visual.Menyetujui hal pengecualian, meskipun. Tapi setidaknya bagi saya, sebagian besar menggunakan
as
boil down untuk memeriksanull
setelahnya, yang menurut saya lebih bagus daripada menangkap pengecualian.sumber
99% waktu saya menggunakan "as" adalah ketika saya tidak yakin apa tipe objek yang sebenarnya
dan saya tidak ingin menangkap pengecualian pemain eksplisit atau membuat pemain dua kali, menggunakan "is":
sumber
as
. Apa yang 1% lainnya?Hanya karena orang menyukai tampilannya, ini sangat mudah dibaca.
Mari kita hadapi itu: operator casting / konversi dalam bahasa seperti-C cukup mengerikan, mudah dibaca. Saya ingin lebih baik jika C # mengadopsi sintaks Javascript:
Atau tentukan
to
operator, setara dengan castingas
:sumber
dynamic_cast<>()
(dan serupa). Anda melakukan sesuatu yang jelek, itu harus terlihat jelek.Orang-orang
as
sangat menyukainya karena itu membuat mereka merasa aman dari pengecualian ... Seperti jaminan pada sebuah kotak. Seorang pria memberikan jaminan mewah pada kotak itu karena dia ingin Anda merasa hangat dan hangat di dalam kotak. Anda pikir Anda meletakkan kotak kecil itu di bawah bantal Anda di malam hari, Peri Jaminan mungkin turun dan meninggalkan seperempat, apakah saya benar Ted?Kembali ke topik ... saat menggunakan pemain langsung, ada kemungkinan pengecualian pemain tidak valid. Jadi orang berlaku
as
sebagai solusi selimut untuk semua kebutuhan casting mereka karenaas
(dengan sendirinya) tidak akan pernah membuang pengecualian. Tapi lucunya tentang itu, ada dalam contoh yang Anda berikan(x as T).SomeMethod();
Anda perdagangan pengecualian pemain tidak valid untuk pengecualian referensi nol. Yang mengaburkan masalah sebenarnya ketika Anda melihat pengecualian.Saya biasanya tidak menggunakan
as
terlalu banyak. Saya lebih sukais
tes karena bagi saya, tampaknya lebih mudah dibaca dan lebih masuk akal daripada mencoba pemain dan memeriksa nol.sumber
as
sebagai solusi selimut karena itu membuat mereka merasa aman.Ini pasti salah satu yang paling kencing di antara saya .
D&E Stroustrup dan / atau beberapa posting blog yang tidak dapat saya temukan saat ini membahas gagasan tentang
to
operator yang akan membahas poin yang dibuat oleh https://stackoverflow.com/users/73070/johannes-rossel (yaitu, sintaksis yang samaas
tetapi denganDirectCast
semantik) ).Alasan mengapa ini tidak diterapkan adalah karena pemain harus menyebabkan rasa sakit dan menjadi jelek sehingga Anda terdorong untuk tidak menggunakannya.
Kasihan bahwa programmer 'pintar' (sering penulis buku (Juval Lowy IIRC)) melangkah sekitar ini dengan menyalahgunakan
as
dengan cara ini (C ++ tidak menawarkanas
, mungkin karena alasan ini).Bahkan VB memiliki konsistensi lebih dalam memiliki sintaks seragam yang memaksa Anda untuk memilih
TryCast
atauDirectCast
dan membuat pikiran Anda !sumber
DirectCast
perilaku , bukan sintaksis .semantics
: Pdouble-to-int
pemain yang akan gagal jikadouble
tidak mewakili nilai tepat yang bisa masukInt32
, tetapi memiliki(int)-1.5
hasil -1 hanyalah jelek.MaybeValid<T>
dua bidang publikIsValid
danValue
kode mana yang bisa dilakukan sesuai dengan keinginan. Itu akan memungkinkan misalnyaMaybeValid<TValue> TryGetValue(TKey key) { var ret = default(MaybeValid<TValue>); ret.IsValid = dict.TryGetValue(key, out ret.Value); return ret; }
. Tidak hanya akan menghemat setidaknya dua operasi penyalinan dibandingkan denganNullable<T>
, tetapi juga bisa bernilai dengan jenis apa pun -T
bukan hanya kelas.Saya percaya bahwa
as
kata kunci dapat dianggap sebagai versi yang lebih elegandynamic_cast
dari C ++.sumber
dynamic_cast
di C ++.std::bad_cast
.static_cast
tidak melakukan pemeriksaan jenis runtime. Tidak ada pemeran yang serupa dengan ini di C #.Mungkin lebih populer tanpa alasan teknis tetapi hanya karena lebih mudah dibaca dan lebih intuitif. (Tidak mengatakan itu membuatnya lebih baik hanya mencoba menjawab pertanyaan)
sumber
Salah satu alasan untuk menggunakan "sebagai":
Alih-alih (kode buruk):
sumber
obj
berarti mengubahobj
variabel itu sendiri untuk menyimpan referensi ke objek lain. Itu tidak akan mengubah isi memori di mana berada objek awalnya dirujuk olehobj
. Objek asli ini akan tetap tidak berubah, dant
variabel masih akan menyimpan referensi untuk itu.