C# Casting a List as List

前端 未结 11 1523
小鲜肉
小鲜肉 2020-12-09 15:35

Why can I not cast a List as List? Why does the following not work:

internal class ObjBase
   {
   }

int         


        
相关标签:
11条回答
  • 2020-12-09 16:11

    You can use Cast and ToList extension methods from System.Linq to have this in one line.

    Instead of

    internal List<Obj> returnStuff()
    {
       return getSomeStuff() as List<Obj>;
    }
    

    do this:

    internal List<Obj> returnStuff()
    {
       return getSomeStuff().Cast<Obj>().ToList();
    }
    
    0 讨论(0)
  • 2020-12-09 16:11

    Linq has a ConvertAll method. so something like

    list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));
    

    I'm not sure what else to suggest. I assume ObjBase is the base class, and if all ObjBase objects are Obj objects, i'm not sure why you would have the two objects in the first place. Perhaps i'm off the mark.

    Edit: the list.Cast method would work better than the above, assuming they are castable to each other. Forgot about that until I read the other answers.

    0 讨论(0)
  • 2020-12-09 16:13

    Please look at the following questions:

    .NET Casting Generic List

    Why does this generic cast fail?

    0 讨论(0)
  • 2020-12-09 16:18

    list.ConvertAll looks tempting but has 1 big disadvantage: it will create a whole new list. This will impact performance and memory usage especially for big lists.

    With a bit more effort you can create a wrapper list class that keeps the original list as an internal reference, and convert the items only when they are used.

    Usage:

    var x = new List<ObjBase>();
    var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>
    

    Code to add to your library:

    public static class Extensions
    {
        public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
        {
            return new CastedList<TTo, TFrom>(list);
        }
    }
    
    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; } }
    }
    
    0 讨论(0)
  • 2020-12-09 16:23

    C# currently does not support variance for generic types. From what I've read, this will change in 4.0.

    See here for more information on variance in generics.

    0 讨论(0)
提交回复
热议问题