Bahkan jika Anda mungkin melihatnya sebagai padanan, tujuan mereka sama sekali berbeda. Pertama-tama, mari kita coba mendefinisikan apa itu pemeran:
Transmisi adalah tindakan mengubah entitas dari satu tipe data menjadi yang lain.
Ini sedikit umum dan entah bagaimana setara dengan konversi karena pemeran sering memiliki sintaks yang sama dari konversi sehingga pertanyaannya adalah kapan pemeran (implisit atau eksplisit) diizinkan oleh bahasa dan kapan Anda harus menggunakan ( lebih) konversi eksplisit?
Izinkan saya menggambar garis sederhana di antara mereka. Secara formal (bahkan jika setara untuk sintaks bahasa) cast akan mengubah jenis sementara konversi akan / dapat mengubah nilai (akhirnya bersama dengan jenis). Juga pemeran dapat dibalik sementara konversi mungkin tidak.
Topik ini sangat luas jadi mari kita coba mempersempitnya sedikit dengan mengecualikan operator cast kustom dari game.
Pemeran implisit
Dalam C #, cast tersirat ketika Anda tidak akan kehilangan informasi apa pun (harap dicatat bahwa pemeriksaan ini dilakukan dengan tipe dan bukan dengan nilai sebenarnya ).
Tipe primitif
Sebagai contoh:
int tinyInteger = 10;
long bigInteger = tinyInteger;
float tinyReal = 10.0f;
double bigReal = tinyReal;
Pemeran ini tersirat karena selama konversi Anda tidak akan kehilangan informasi apa pun (Anda hanya membuat jenisnya lebih luas). Sebaliknya, cast implisit tidak diizinkan karena, terlepas dari nilai sebenarnya (karena hanya dapat diperiksa pada waktu proses), selama konversi Anda mungkin kehilangan beberapa informasi. Misalnya, kode ini tidak dapat dikompilasi karena a doublemay berisi (dan sebenarnya memang demikian) nilai yang tidak dapat direpresentasikan dengan float:
double bigReal = Double.MaxValue;
float tinyReal = bigReal;
Objek
Dalam kasus objek (penunjuk ke) cast selalu implisit ketika compiler dapat memastikan bahwa tipe sumber adalah kelas turunan (atau mengimplementasikan) jenis kelas target, misalnya:
string text = "123";
IFormattable formattable = text;
NotSupportedException derivedException = new NotSupportedException();
Exception baseException = derivedException;
Dalam hal ini compiler tahu bahwa stringalat IFormattabledan bahwa NotSupportedExceptionadalah (atau diperoleh dari) Exceptionsehingga pemain tersirat. Tidak ada informasi yang hilang karena objek tidak mengubah tipenya (ini berbeda dengan structtipe s dan primitif karena dengan cast Anda membuat objek baru dari tipe lain ), yang berubah adalah pandangan Anda terhadapnya.
Pemeran eksplisit
Sebuah cast eksplisit ketika konversi tidak dilakukan secara implisit oleh compiler dan kemudian Anda harus menggunakan operator cast. Biasanya itu berarti:
- Anda mungkin kehilangan informasi atau data sehingga Anda harus menyadarinya.
- Konversi mungkin gagal (karena Anda tidak dapat mengonversi satu jenis ke jenis lainnya) jadi, sekali lagi, Anda harus menyadari apa yang Anda lakukan.
Tipe primitif
Cast eksplisit diperlukan untuk tipe primitif ketika selama konversi Anda mungkin kehilangan beberapa data, misalnya:
double precise = Math.Cos(Math.PI * 1.23456) / Math.Sin(1.23456);
float coarse = (float)precise;
float epsilon = (float)Double.Epsilon;
Dalam kedua contoh tersebut, meskipun nilainya berada dalam floatkisaran, Anda akan kehilangan informasi (dalam hal ini presisi) sehingga konversinya harus eksplisit. Sekarang coba ini:
float max = (float)Double.MaxValue;
Konversi ini akan gagal jadi, sekali lagi, harus eksplisit sehingga Anda menyadarinya dan Anda dapat melakukan pemeriksaan (dalam contoh, nilainya konstan tetapi mungkin berasal dari beberapa penghitungan run-time atau I / O). Kembali ke contoh Anda:
string text = "123";
double value = (double)text;
Ini tidak dapat dikompilasi karena kompilator tidak dapat mengubah teks menjadi angka. Teks dapat berisi karakter apa pun, bukan hanya angka dan ini terlalu banyak, di C #, bahkan untuk pemeran eksplisit (tetapi mungkin diizinkan dalam bahasa lain).
Objek
Konversi dari pointer (ke objek) mungkin gagal jika tipenya tidak terkait, misalnya kode ini tidak akan dikompilasi (karena kompilator tahu tidak ada kemungkinan konversi):
string text = (string)AppDomain.Current;
Exception exception = (Exception)"abc";
Kode ini akan dikompilasi tetapi mungkin gagal saat run-time (tergantung pada jenis objek yang dicor) dengan InvalidCastException:
object obj = GetNextObjectFromInput();
string text = (string)obj;
obj = GetNextObjectFromInput();
Exception exception = (Exception)obj;
Konversi
Jadi, akhirnya, jika pemain adalah konversi lalu mengapa kita membutuhkan kelas seperti itu Convert? Mengabaikan perbedaan halus yang berasal dari Convertimplementasi dan IConvertibleimplementasi sebenarnya karena di C # dengan cast yang Anda katakan kepada compiler:
percayalah, tipe ini adalah tipe itu bahkan jika Anda tidak dapat mengetahuinya sekarang, biarkan saya melakukannya dan Anda akan melihatnya.
-atau-
jangan khawatir, saya tidak peduli jika sesuatu akan hilang dalam pertobatan ini.
Untuk hal lain, operasi yang lebih eksplisit diperlukan (pikirkan tentang implikasi cast yang mudah , itulah mengapa C ++ memperkenalkan sintaks yang panjang, verbose, dan eksplisit untuk mereka). Ini mungkin melibatkan operasi yang kompleks (untuk string-> doublekonversi diperlukan penguraian). Konversi ke string, misalnya, selalu memungkinkan (melalui ToString()metode) tetapi itu mungkin berarti sesuatu yang berbeda dari yang Anda harapkan sehingga harus lebih eksplisit daripada pemeran ( lebih banyak Anda menulis, lebih banyak Anda memikirkan apa yang Anda lakukan ).
Konversi ini dapat dilakukan di dalam objek (menggunakan instruksi IL yang diketahui untuk itu), menggunakan operator konversi kustom (ditentukan di kelas yang akan ditransmisikan) atau mekanisme yang lebih kompleks ( TypeConverters atau metode kelas, misalnya). Anda tidak mengetahui apa yang akan terjadi untuk melakukan itu tetapi Anda sadar itu mungkin gagal (itulah mengapa IMO ketika konversi yang lebih terkontrol dimungkinkan, Anda harus menggunakannya). Dalam kasus Anda, konversi hanya akan mengurai stringmenjadi double:
double value = Double.Parse(aStringVariable);
Tentu saja ini mungkin gagal jadi jika Anda melakukannya, Anda harus selalu menangkap pengecualian yang mungkin dilontarkan ( FormatException). Ini di luar topik di sini tetapi ketika a TryParsetersedia maka Anda harus menggunakannya (karena secara semantik Anda mengatakan itu mungkin bukan angka dan bahkan lebih cepat ... gagal).
Konversi dalam .NET dapat berasal dari banyak tempat TypeConverter,,, pemeran implisit / eksplisit dengan operator konversi yang ditentukan pengguna, implementasi IConvertibledan metode parsing (apakah saya lupa sesuatu?). Lihat MSDN untuk detail lebih lanjut tentang mereka.
Untuk menyelesaikan jawaban panjang ini, hanya beberapa kata tentang operator konversi yang ditentukan pengguna. Hanya gula untuk membiarkan programmer menggunakan pemeran untuk mengubah satu jenis ke jenis lainnya. Ini adalah metode di dalam kelas (yang akan dicor) yang mengatakan "hei, jika dia ingin mengubah tipe ini ke tipe itu maka saya bisa melakukannya". Sebagai contoh:
float? maybe = 10;
float sure1 = (float)maybe;
float sure2 = maybe.Value;
Dalam hal ini eksplisit karena mungkin gagal tetapi ini dibiarkan untuk implementasi (meskipun ada pedoman tentang ini). Bayangkan Anda menulis kelas string kustom seperti ini:
EasyString text = "123";
double value = (string)text;
Dalam implementasi Anda, Anda mungkin memutuskan untuk "membuat hidup programmer lebih mudah" dan mengekspos konversi ini melalui cast (ingat itu hanya jalan pintas untuk menulis lebih sedikit). Beberapa bahasa bahkan mungkin mengizinkan ini:
double value = "123";
Mengizinkan konversi implisit ke jenis apa pun (pemeriksaan akan dilakukan pada waktu proses). Dengan opsi yang tepat ini dapat dilakukan, misalnya, di VB.NET. Itu hanya filosofi yang berbeda.
Apa yang dapat saya lakukan dengan mereka?
Jadi pertanyaan terakhir adalah kapan Anda harus menggunakan satu atau lainnya. Mari kita lihat kapan Anda dapat menggunakan pemeran eksplisit:
- Konversi antara jenis dasar.
- Konversi dari
objectke jenis lain (ini mungkin termasuk membuka kemasan juga).
- Konversi dari kelas turunan ke kelas dasar (atau ke antarmuka yang diimplementasikan).
- Konversi dari satu jenis ke jenis lainnya melalui operator konversi kustom.
Hanya konversi pertama yang dapat dilakukan, Convertjadi untuk yang lain Anda tidak punya pilihan dan Anda perlu menggunakan pemeran eksplisit.
Mari kita lihat sekarang kapan Anda dapat menggunakan Convert:
- Konversi dari jenis dasar apa pun ke jenis dasar lain (dengan beberapa batasan, lihat MSDN ).
- Konversi dari jenis apa pun yang diterapkan
IConvertibleke jenis lain (didukung).
- Konversi dari / ke
bytelarik ke / dari string.
Kesimpulan
IMO Convertharus digunakan setiap kali Anda mengetahui konversi mungkin gagal (karena formatnya, karena rentangnya atau karena mungkin tidak didukung), bahkan jika konversi yang sama dapat dilakukan dengan cast (kecuali ada hal lain yang tersedia). Ini menjelaskan siapa yang akan membaca kode Anda apa maksud Anda dan bahwa kode itu mungkin gagal (menyederhanakan debug).
Untuk semua hal lain Anda perlu menggunakan pemeran, tidak ada pilihan, tetapi jika metode lain yang lebih baik tersedia maka saya sarankan Anda menggunakannya. Dalam contoh Anda, konversi dari stringke doubleadalah sesuatu yang (terutama jika teks berasal dari pengguna) sering kali akan gagal, jadi Anda harus membuatnya sedetail mungkin (selain itu Anda mendapatkan kontrol lebih besar), misalnya menggunakan TryParsemetode.
Sunting: apa perbedaan di antara mereka?
Menurut pertanyaan yang diperbarui dan menyimpan apa yang saya tulis sebelumnya (tentang kapan Anda dapat menggunakan pemeran dibandingkan dengan kapan Anda dapat / harus menggunakan Convert) maka poin terakhir yang harus diperjelas adalah jika ada perbedaan di antara mereka (apalagi Convertpenggunaan IConvertibledan IFormattableantarmuka sehingga dapat melakukan operasi tidak diperbolehkan dengan gips).
Jawaban singkatnya adalah ya, mereka berperilaku berbeda . Saya melihat Convertkelas seperti kelas metode penolong begitu sering memberikan beberapa manfaat atau perilaku yang sedikit berbeda. Sebagai contoh:
double real = 1.6;
int castedInteger = (int)real;
int convertedInteger = Convert.ToInt32(real);
Sangat berbeda, bukan? Cast memotong (itulah yang kita semua harapkan) tetapi Convertmelakukan pembulatan ke integer terdekat (dan ini mungkin tidak diharapkan jika Anda tidak menyadarinya). Setiap metode konversi memperkenalkan perbedaan sehingga aturan umum tidak dapat diterapkan dan harus dilihat kasus per kasus ... 19 jenis dasar untuk dikonversi ke setiap jenis lainnya ... daftar bisa sangat panjang, jauh lebih baik untuk berkonsultasi kasus MSDN dengan kasus!