Untuk menambah poin Sweko:
Alasan mengapa para pemain
var listOfX = new List<X>();
ListOf<Y> ys = (List<Y>)listOfX; // Compile error: Cannot implicitly cast X to Y
tidak mungkin karena List<T>
adalah invarian dalam Type T dan dengan demikian tidak peduli apakah X
atau diperoleh dari Y
) - ini karena List<T>
didefinisikan sebagai:
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T> ... // Other interfaces
(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 dari Animal
:
IEnumerable<Animal> animals = giraffes;
Ini karena IEnumerable<T>
mendukung kovarian dalam T
- ini masuk akal mengingat bahwa IEnumerable
menyiratkan koleksi tidak dapat diubah, karena tidak memiliki dukungan untuk metode untuk Menambahkan atau Menghapus elemen dari koleksi. Perhatikan out
kata kunci dalam deklarasi IEnumerable<T>
:
public interface IEnumerable<out T> : IEnumerable
( Berikut penjelasan lebih lanjut untuk alasan mengapa koleksi yang bisa berubah seperti List
tidak dapat mendukung covariance
, 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 elemen InvalidCastException
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 dalam foreach
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 eksplisitY y
di foreach
)
List<Y> ListOfY = new List<Y>();
foreach(Y y in ListOfX)
{
ListOfY.Add(y);
}
bahwa casting juga akan dicoba. Namun, jika tidak ada pemeran yang mungkin, InvalidCastException
hasil akan.
Contohnya
Misalnya, dengan hierarki kelas sederhana (C # 6):
public abstract class Animal
{
public string Name { get; }
protected Animal(string name) { Name = name; }
}
public class Elephant : Animal
{
public Elephant(string name) : base(name){}
}
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
}
Saat bekerja dengan koleksi jenis campuran:
var mixedAnimals = new Animal[]
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach(Animal animal in mixedAnimals)
{
// Fails for Zed - `InvalidCastException - cannot cast from Zebra to Elephant`
castedAnimals.Add((Elephant)animal);
}
var castedAnimals = mixedAnimals.Cast<Elephant>()
// Also fails for Zed with `InvalidCastException
.ToList();
Sedangkan:
var castedAnimals = mixedAnimals.OfType<Elephant>()
.ToList();
// Ellie
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:
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
public static implicit operator Elephant(Zebra z)
{
return new Elephant(z.Name);
}
}
Alih-alih, mengingat operator konversi di atas, kompiler akan dapat mengubah jenis array di bawah ini dari Animal[]
menjadi Elephant[]
, mengingat bahwa Zebra sekarang dapat dikonversi ke koleksi Gajah yang homogen:
var compilerInferredAnimals = new []
{
new Zebra("Zed"),
new Elephant("Ellie")
};
Menggunakan Operator Konversi Implisit pada waktu berjalan
* Seperti yang disebutkan oleh Eric, operator konversi dapat diakses pada waktu berjalan dengan beralih ke dynamic
:
var mixedAnimals = new Animal[] // i.e. Polymorphic collection
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach (dynamic animal in mixedAnimals)
{
castedAnimals.Add(animal);
}
// Returns Zed, Ellie