에릭의 위대한 설명을 인용하자면
무슨 일이야? 기린 목록에 호랑이가 포함되도록 하시겠습니까? 충돌을 원하십니까? 아니면 처음부터 할당을 불법으로 만들어 컴파일러가 충돌로부터 보호하기를 원하십니까? 우리는 후자를 선택합니다.
그러나 컴파일 오류 대신 런타임 충돌을 선택하려면 어떻게해야합니까? 일반적으로 Cast <> 또는 ConvertAll <>을 사용하지만 두 가지 문제가 있습니다. 목록의 사본이 작성됩니다. 새 목록에서 무언가를 추가하거나 제거하면 원래 목록에 반영되지 않습니다. 둘째, 기존 객체로 새 목록을 작성하므로 성능과 메모리가 크게 저하됩니다.
나는 같은 문제가 있었으므로 완전히 새로운 목록을 만들지 않고 일반 목록을 캐스팅 할 수있는 래퍼 클래스를 만들었습니다.
원래 질문에서 다음을 사용할 수 있습니다.
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
IList<A> listOfA = new List<C>().CastList<C,A>(); // now ok!
}
}
그리고 여기 래퍼 클래스 (+ 사용하기 쉬운 확장 메소드 CastList)
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);
}
}