Saya tahu ini mungkin untuk melemparkan daftar item dari satu jenis ke yang lain (mengingat bahwa objek Anda memiliki metode operator publik statis statis untuk melakukan casting) satu per satu sebagai berikut:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Tetapi apakah tidak mungkin untuk melemparkan seluruh daftar sekaligus? Sebagai contoh,
ListOfY = (List<Y>)ListOfX;
c#
list
casting
ienumerable
Jimbo
sumber
sumber
Jawaban:
Jika
X
benar-benar dapat dilemparkan keY
Anda harus dapat menggunakanBeberapa hal yang harus diperhatikan (H / T kepada komentator!)
using System.Linq;
untuk mendapatkan metode ekstensi iniList<Y>
akan dibuat oleh panggilan keToList()
.sumber
Cast<T>
metode tidak mendukung operator konversi khusus. Mengapa Linq Cast Helper Tidak Bekerja dengan Operator Cast Implisit .Pemain langsung
var ListOfY = (List<Y>)ListOfX
tidak mungkin karena akan membutuhkan co / contravariance dariList<T>
jenis, dan itu tidak dapat dijamin dalam setiap kasus. Baca terus untuk melihat solusi untuk masalah casting ini.Meskipun tampaknya normal untuk dapat menulis kode seperti ini:
karena kami dapat menjamin bahwa setiap mamalia akan menjadi binatang, ini jelas sebuah kesalahan:
karena tidak setiap binatang adalah mamalia.
Namun, menggunakan C # 3 dan di atas, Anda dapat menggunakan
yang memudahkan casting sedikit. Ini secara sintaksis setara dengan kode Anda menambahkan satu-per-satu, karena menggunakan pemeran eksplisit untuk masing-masing melemparkan
Mammal
dalam daftar keAnimal
, dan akan gagal jika pemeran tidak berhasil.Jika Anda suka kontrol lebih besar atas proses casting / konversi, Anda bisa menggunakan
ConvertAll
metodeList<T>
kelas, yang bisa menggunakan ekspresi yang disediakan untuk mengonversi item. Ini memiliki manfaat tambahan yang mengembalikanList
, bukannyaIEnumerable
, jadi tidak.ToList()
perlu.sumber
Untuk menambah poin Sweko:
Alasan mengapa para pemain
tidak mungkin karena
List<T>
adalah invarian dalam Type T dan dengan demikian tidak peduli apakahX
atau diperoleh dariY
) - ini karenaList<T>
didefinisikan sebagai:(Perhatikan bahwa dalam deklarasi ini, ketik di
T
sini tidak memiliki pengubah varian tambahan)Namun, jika koleksi bisa berubah tidak diperlukan dalam desain Anda, sebuah upcast pada banyak koleksi berubah, mungkin , misalnya asalkan
Giraffe
atau diperoleh dariAnimal
:Ini karena
IEnumerable<T>
mendukung kovarian dalamT
- ini masuk akal mengingat bahwaIEnumerable
menyiratkan koleksi tidak dapat diubah, karena tidak memiliki dukungan untuk metode untuk Menambahkan atau Menghapus elemen dari koleksi. Perhatikanout
kata kunci dalam deklarasiIEnumerable<T>
:( Berikut penjelasan lebih lanjut untuk alasan mengapa koleksi yang bisa berubah seperti
List
tidak dapat mendukungcovariance
, sedangkan iterator dan koleksi yang tidak dapat diubah dapat.)Casting dengan
.Cast<T>()
Seperti yang telah disebutkan orang lain,
.Cast<T>()
dapat diterapkan pada koleksi untuk memproyeksikan koleksi baru elemenInvalidCastException
yang dilemparkan ke T, namun hal itu akan melempar jika cor pada satu atau lebih elemen tidak mungkin (yang akan menjadi perilaku yang sama seperti melakukan eksplisit masukkan dalamforeach
loop OP ).Filter dan Casting dengan
OfType<T>()
Jika daftar input berisi elemen-elemen dengan tipe yang berbeda dan tidak dapat dilawan, potensi
InvalidCastException
dapat dihindari dengan menggunakan.OfType<T>()
alih-alih.Cast<T>()
. (.OfType<>()
memeriksa untuk melihat apakah suatu elemen dapat dikonversi ke jenis target, sebelum mencoba konversi, dan memfilter jenis yang tidak dapat dilompati.)untuk setiap
Perhatikan juga bahwa jika OP yang menulis ini sebagai gantinya: (catat eksplisit
Y y
diforeach
)bahwa casting juga akan dicoba. Namun, jika tidak ada pemeran yang mungkin,
InvalidCastException
hasil akan.Contohnya
Misalnya, dengan hierarki kelas sederhana (C # 6):
Saat bekerja dengan koleksi jenis campuran:
Sedangkan:
hanya menyaring Gajah - yaitu Zebra dihilangkan.
Re: Operator pemain implisit
Tanpa dinamis, operator konversi yang ditentukan pengguna hanya digunakan pada waktu kompilasi *, jadi bahkan jika operator konversi antara katakanlah Zebra dan Elephant tersedia, perilaku waktu berjalan di atas dari pendekatan konversi tidak akan berubah.
Jika kami menambahkan operator konversi untuk mengubah Zebra menjadi Gajah:
Alih-alih, mengingat operator konversi di atas, kompiler akan dapat mengubah jenis array di bawah ini dari
Animal[]
menjadiElephant[]
, mengingat bahwa Zebra sekarang dapat dikonversi ke koleksi Gajah yang homogen:Menggunakan Operator Konversi Implisit pada waktu berjalan
* Seperti yang disebutkan oleh Eric, operator konversi dapat diakses pada waktu berjalan dengan beralih ke
dynamic
:sumber
foreach
tidak memfilter, tetapi menggunakan tipe yang lebih diturunkan sebagai variabel iterasi akan memaksa kompiler untuk mencoba Cast, yang akan gagal pada elemen pertama yang tidak mematuhinya.Kamu bisa memakai
List<Y>.ConvertAll<T>([Converter from Y to T]);
sumber
Ini bukan jawaban yang tepat untuk pertanyaan ini, tetapi mungkin bermanfaat bagi beberapa orang: seperti yang dikatakan @SWeko, terima kasih kepada kovarians dan contravariance,
List<X>
tidak dapat dilemparkan ke dalamList<Y>
, tetapiList<X>
dapat dilemparkan ke dalamIEnumerable<Y>
, dan bahkan dengan pemeran implisit.Contoh:
tapi
Keuntungan besar adalah tidak membuat daftar baru di memori.
sumber
sumber