Mengutip penjelasan hebat Eric
Apa yang terjadi? Apakah Anda ingin daftar jerapah mengandung harimau? Apakah Anda ingin crash? atau apakah Anda ingin kompiler melindungi Anda dari crash dengan menjadikan tugas itu ilegal? Kami memilih yang terakhir.
Tetapi bagaimana jika Anda ingin memilih untuk crash runtime daripada kesalahan kompilasi? Anda biasanya menggunakan Cast <> atau ConvertAll <> tetapi kemudian Anda akan memiliki 2 masalah: Ini akan membuat salinan daftar. Jika Anda menambahkan atau menghapus sesuatu di daftar baru, ini tidak akan tercermin dalam daftar asli. Dan kedua, ada performa besar dan hukuman memori karena membuat daftar baru dengan objek yang ada.
Saya memiliki masalah yang sama dan karena itu saya membuat kelas pembungkus yang dapat membuat daftar generik tanpa membuat daftar yang sama sekali baru.
Dalam pertanyaan awal, Anda dapat menggunakan:
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
IList<A> listOfA = new List<C>().CastList<C,A>(); // now ok!
}
}
dan di sini kelas wrapper (+ metode extention CastList agar mudah digunakan)
public class CastedList<TTo, TFrom> : IList<TTo>
{
public IList<TFrom> BaseList;
public CastedList(IList<TFrom> baseList)
{
BaseList = baseList;
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }
// IEnumerable<>
public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }
// ICollection
public int Count { get { return BaseList.Count; } }
public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
public void Clear() { BaseList.Clear(); }
public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }
// IList
public TTo this[int index]
{
get { return (TTo)(object)BaseList[index]; }
set { BaseList[index] = (TFrom)(object)value; }
}
public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}
public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
public IEnumerator<TFrom> BaseEnumerator;
public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
{
BaseEnumerator = baseEnumerator;
}
// IDisposable
public void Dispose() { BaseEnumerator.Dispose(); }
// IEnumerator
object IEnumerator.Current { get { return BaseEnumerator.Current; } }
public bool MoveNext() { return BaseEnumerator.MoveNext(); }
public void Reset() { BaseEnumerator.Reset(); }
// IEnumerator<>
public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}
public static class ListExtensions
{
public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
{
return new CastedList<TTo, TFrom>(list);
}
}