Trích dẫn lời giải thích tuyệt vời của Eric
Chuyện gì xảy ra Bạn có muốn danh sách hươu cao cổ có chứa một con hổ? Bạn có muốn một vụ tai nạn? hoặc bạn muốn trình biên dịch bảo vệ bạn khỏi sự cố bằng cách chuyển nhượng bất hợp pháp ngay từ đầu? Chúng tôi chọn cái sau.
Nhưng nếu bạn muốn chọn cho một sự cố thời gian chạy thay vì một lỗi biên dịch thì sao? Thông thường bạn sẽ sử dụng Cast <> hoặc Convert ALL <> nhưng sau đó bạn sẽ gặp 2 vấn đề: Nó sẽ tạo một bản sao của danh sách. Nếu bạn thêm hoặc xóa một cái gì đó trong danh sách mới, điều này sẽ không được phản ánh trong danh sách ban đầu. Và thứ hai, có một hình phạt hiệu năng và bộ nhớ lớn vì nó tạo ra một danh sách mới với các đối tượng hiện có.
Tôi có cùng một vấn đề và do đó tôi đã tạo ra một lớp bao bọc có thể tạo một danh sách chung mà không tạo ra một danh sách hoàn toàn mới.
Trong câu hỏi ban đầu bạn có thể sử dụng:
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
IList<A> listOfA = new List<C>().CastList<C,A>(); // now ok!
}
}
và ở đây lớp trình bao bọc (+ một phương thức mở rộng CastList để dễ sử dụng)
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);
}
}