C# Casting a List<ObjBase> as List<Obj>
Solution 1
Please look at the following questions:
Why does this generic cast fail?
Solution 2
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();
}
Solution 3
I can only describe the "problem" from a Java view, but from what little I know this aspect is the same in both C# and Java:
A List<ObjBase>
is not a List<Obj>
, because it could contain an ObjBase
object which is not a Obj
object.
The other way around a List<Obj>
can not be cast to a List<ObjBase>
because the former guarantees to accept an Add()
call with a ObjBase
argument, which the latter will not accept!
So to summarize: even though a Obj
is-a ObjBase
a List<Obj>
is not a List<ObjBase>
.
Solution 4
Covariance my friend. Look at http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance
Solution 5
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; } }
}
Comments
-
Mohammad Heydari over 3 years
Why can I not cast a
List<ObjBase>
asList<Obj>
? Why does the following not work:internal class ObjBase { } internal class Obj : ObjBase { } internal class ObjManager { internal List<Obj> returnStuff() { return getSomeStuff() as List<Obj>; } private List<ObjBase> getSomeStuff() { return new List<ObjBase>(); } }
Instead I have to do this:
internal class ObjBase { } internal class Obj : ObjBase { } internal class ObjManager { internal List<Obj> returnStuff() { List<ObjBase> returnedList = getSomeStuff(); List<Obj> listToReturn = new List<Obj>(returnedList.Count); foreach (ObjBase currentBaseObject in returnedList) { listToReturn.Add(currentBaseObject as Obj); } return listToReturn; } private List<ObjBase> getSomeStuff() { return new List<ObjBase>(); } }
I get the following error in Visual Studio 2008 (shortened for readability):
Cannot convert type 'List' to 'List' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
Thanks.