By Asad Butt


2009-11-30 00:31:21 8 Comments

While we can inherit from base class/interface, why can't we declare a List<> using same class/interface?

interface A
{ }

class B : A
{ }

class C : B
{ }

class Test
{
    static void Main(string[] args)
    {
        A a = new C(); // OK
        List<A> listOfA = new List<C>(); // compiler Error
    }
}

Is there a way around?

10 comments

@Drew 2019-06-16 21:09:41

You can also use the System.Runtime.CompilerServices.Unsafe NuGet package to create a reference to the same List:

using System.Runtime.CompilerServices;
...
class Tool { }
class Hammer : Tool { }
...
var hammers = new List<Hammer>();
...
var tools = Unsafe.As<List<Tool>>(hammers);

Given the sample above, you can access the existing Hammer instances in the list using the tools variable. Adding Tool instances to the list throws an ArrayTypeMismatchException exception because tools references the same variable as hammers.

@vikingfabian 2018-04-21 15:55:28

I personally like to create libs with extensions to the classes

public static List<TTo> Cast<TFrom, TTo>(List<TFrom> fromlist)
  where TFrom : class 
  where TTo : class
{
  return fromlist.ConvertAll(x => x as TTo);
}

@PhistucK 2015-02-25 14:32:30

If you use IEnumerable instead, it will work (at least in C# 4.0, I have not tried previous versions). This is just a cast, of course, it will still be a list.

Instead of -

List<A> listOfA = new List<C>(); // compiler Error

In the original code of the question, use -

IEnumerable<A> listOfA = new List<C>(); // compiler error - no more! :)

@Vladius 2015-12-14 12:12:33

How to use the IEnumerable in that case exactly?

@PhistucK 2015-12-14 16:39:55

Instead of List<A> listOfA = new List<C>(); // compiler Error in the original code of the question, enter IEnumerable<A> listOfA = new List<C>(); // compiler error - no more! :)

@beauXjames 2015-12-15 17:00:54

The method taking the IEnumerable<BaseClass> as a parameter will allow for the inherited class to be passed in as a List. So there's very little to do but change the parameter type.

@Bigjim 2015-06-05 09:01:35

To quote the great explanation of Eric

What happens? Do you want the list of giraffes to contain a tiger? Do you want a crash? or do you want the compiler to protect you from the crash by making the assignment illegal in the first place? We choose the latter.

But what if you want to choose for a runtime crash instead of a compile error? You would normally use Cast<> or ConvertAll<> but then you will have 2 problems: It will create a copy of the list. If you add or remove something in the new list, this won't be reflected in the original list. And secondly, there is a big performance and memory penalty since it creates a new list with the existing objects.

I had the same problem and therefore I created a wrapper class that can cast a generic list without creating an entirely new list.

In the original question you could then use:

class Test
{
    static void Main(string[] args)
    {
        A a = new C(); // OK
        IList<A> listOfA = new List<C>().CastList<C,A>(); // now ok!
    }
}

and here the wrapper class (+ an extention method CastList for easy use)

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);
    }
}

@Paul Coldrey 2016-01-29 06:12:47

Now this is a BRILLIANT answer - I cannot understand which this doesn't have all the votes!

@Stefan Cebulak 2016-10-22 21:14:49

I've just used it as MVC view model and got nice universal razor partial view. Amazing idea! I'm so happy that i read this.

@Wolfzoon 2016-11-02 16:28:55

I would only add a "where TTo : TFrom" at the class declaration, so the compiler can warn against incorrect usage. Making a CastedList of unrelated types is nonsensical anyway, and making a "CastedList<TBase, TDerived>" would be useless: You can't add regular TBase objects to it, and any TDerived you get from the original List can already be used as a TBase.

@Wolfzoon 2016-11-02 16:31:17

@PaulColdrey Alas, a six year head start is to blame.

@Bigjim 2017-04-12 11:13:08

@Wolfzoon: the standard .Cast<T>() hasn't this restriction either. I wanted to make the behaviour the same as .Cast so it is possible to cast a list of Animals to a list of Tigers, and have an exception when it would contain a Giraffe for example. Just as it would be with Cast...

@Denis Vitez 2018-04-16 11:45:09

Hi @Bigjim, I'm having problems understanding how to use your wrapper class, to cast an existing array of Giraffes into an array of Animals (base class). Any tips will be appriciated :)

@Wojciech Mikołajewicz 2017-03-16 12:52:51

You can only cast to readonly lists. For example:

IEnumerable<A> enumOfA = new List<C>();//This works
IReadOnlyCollection<A> ro_colOfA = new List<C>();//This works
IReadOnlyList<A> ro_listOfA = new List<C>();//This works

And you cannot do it for lists that support saving elements. The reason why is:

List<string> listString=new List<string>();
List<object> listObject=(List<object>)listString;//Assume that this is possible
listObject.Add(new object());

What now? Remember that listObject and listString are the same list actually, so listString now have object element - it shouldn't be possible and it's not.

@bendtherules 2017-10-14 07:00:41

This one was the most understandable answer to me. Specially because it mentions that there is something called IReadOnlyList, which will work because it guarantees that no more element will be added.

@Alastair Maw 2017-11-30 17:33:48

It's a shame that you can't do similar for IReadOnlyDictionary<TKey, TValue>. Why is that?

@Rick Love 2018-11-02 14:12:22

This is a great suggestion. I use List<> everywhere for convenience, but most of the time I want it to be readonly. Nice suggestion as this will improve my code in 2 ways by allowing this cast and improving where I specify readonly.

@Zach 2016-05-04 01:32:54

This is an extension to BigJim's brilliant answer.

In my case I had a NodeBase class with a Children dictionary, and I needed a way to generically do O(1) lookups from the children. I was attempting to return a private dictionary field in the getter of Children, so obviously I wanted to avoid expensive copying/iterating. Therefore I used Bigjim's code to cast the Dictionary<whatever specific type> to a generic Dictionary<NodeBase>:

// Abstract parent class
public abstract class NodeBase
{
    public abstract IDictionary<string, NodeBase> Children { get; }
    ...
}

// Implementing child class
public class RealNode : NodeBase
{
    private Dictionary<string, RealNode> containedNodes;

    public override IDictionary<string, NodeBase> Children
    {
        // Using a modification of Bigjim's code to cast the Dictionary:
        return new IDictionary<string, NodeBase>().CastDictionary<string, RealNode, NodeBase>();
    }
    ...
}

This worked well. However, I eventually ran into unrelated limitations and ended up creating an abstract FindChild() method in the base class that would do the lookups instead. As it turned out this eliminated the need for the casted dictionary in the first place. (I was able to replace it with a simple IEnumerable for my purposes.)

So the question you might ask (especially if performance is an issue prohibiting you from using .Cast<> or .ConvertAll<>) is:

"Do I really need to cast the entire collection, or can I use an abstract method to hold the special knowledge needed to perform the task and thereby avoid directly accessing the collection?"

Sometimes the simplest solution is the best.

@Chris Pitman 2009-11-30 00:55:20

As far as why it doesn't work, it might be helpful to understand covariance and contravariance.

Just to show why this shouldn't work, here is a change to the code you provided:

void DoesThisWork()
{
     List<C> DerivedList = new List<C>();
     List<A> BaseList = DerivedList;
     BaseList.Add(new B());

     C FirstItem = DerivedList.First();
}

Should this work? The First item in the list is of Type "B", but the type of the DerivedList item is C.

Now, assume that we really just want to make a generic function that operates on a list of some type which implements A, but we don't care what type that is:

void ThisWorks<T>(List<T> GenericList) where T:A
{

}

void Test()
{
     ThisWorks(new List<B>());
     ThisWorks(new List<C>());
}

@Paul Coldrey 2016-01-29 06:19:55

"Should this work?" - I would yes and no. I see no reason why you shouldn't be able to write the code and have it fail at compile time since it is actually doing an invalid conversion at the time you access FirstItem as type 'C'. There are many analogous ways to blow up C# that are supported. IF you actually want to achieve this functionality for a good reason (and there are many) then bigjim's answer below is awesome.

@Noon Silk 2009-11-30 00:32:01

Because C# doesn't allow that type of inheritance conversion at the moment.

@Eric Lippert 2009-11-30 00:40:38

First, this is a question of convertibility, not of inheritance. Second, covariance of generic types will not work on class types, only on interface and delegate types.

@Noon Silk 2009-11-30 00:51:11

Well, I can hardly argue with you.

@Eric Lippert 2009-11-30 00:45:56

First of all, stop using impossible-to-understand class names like A, B, C. Use Animal, Mammal, Giraffe, or Food, Fruit, Orange or something where the relationships are clear.

Your question then is "why can I not assign a list of giraffes to a variable of type list of animal, since I can assign a giraffe to a variable of type animal?"

The answer is: suppose you could. What could then go wrong?

Well, you can add a Tiger to a list of animals. Suppose we allow you to put a list of giraffes in a variable that holds a list of animals. Then you try to add a tiger to that list. What happens? Do you want the list of giraffes to contain a tiger? Do you want a crash? or do you want the compiler to protect you from the crash by making the assignment illegal in the first place?

We choose the latter.

This kind of conversion is called a "covariant" conversion. In C# 4 we will allow you to make covariant conversions on interfaces and delegates when the conversion is known to be always safe. See my blog articles on covariance and contravariance for details. (There will be a fresh one on this topic on both Monday and Thursday of this week.)

@supercat 2011-07-28 15:40:19

Would there be anything unsafe about an IList<T> or ICollection<T> implementing non-generic IList, but implementing having the non-generic Ilist/ICollection return True for IsReadOnly, and throw NotSupportedException for any methods or properties that would modify it?

@Paul Coldrey 2016-01-29 05:55:53

Whilst this answer contains quite acceptable reasoning it is not really "true". The simple answer is that C# doesn't support this. The idea of having a list of animals that contains giraffes and tigers is perfectly valid. The only issue comes when you want to access the higher level classes. In reality this is no different to passing a parent class as a parameter to a function and then trying to cast it to a different sibling class. There may be technical issues with implementing the cast but the explanation above does not provide any reason why it would be a bad idea.

@LINQ 2017-05-08 14:54:30

@EricLippert Why can we do this conversion using an IEnumerable instead of a List? i.e.: List<Animal> listAnimals = listGiraffes as List<Animal>; is not possible, but IEnumerable<Animal> eAnimals = listGiraffes as IEnumerable<Animal> works.

@Eric Lippert 2017-05-08 15:15:07

@jbueno: Read the last paragraph of my answer. The conversion there is known to be safe. Why? Because it is impossible to turn a sequence of giraffes into a sequence of animals and then put a tiger into the sequence of animals. IEnumerable<T> and IEnumerator<T> are both marked as safe for covariance, and the compiler has verified that.

@Mark Byers 2009-11-30 00:43:18

The way to make this work is to iterate over the list and cast the elements. This can be done using ConvertAll:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

You could also use Linq:

List<A> listOfA = new List<C>().Cast<A>().ToList();

@ahaliav fox 2014-07-16 07:56:46

another option: List<A> listOfA = listOfC.ConvertAll(x => (A)x);

@modiX 2014-09-03 10:21:33

Which one is faster? ConvertAll or Cast?

@Bigjim 2015-06-05 09:07:07

This will create a copy of the list. If you add or remove something in the new list, this won't be reflected in the original list. And secondly, there is a big performance and memory penalty since it creates a new list with the existing objects. See my answer below for a solution without these problems.

@Edward 2018-07-13 14:36:16

Answer to modiX: ConvertAll is a method on List<T> , so it will only work on a generic list; it won't work on IEnumerable or IEnumerable<T>; ConvertAll can also do custom conversions not just casting, e.g. ConvertAll(inches => inches * 25.4). Cast<A> is a LINQ extension method, so works on any IEnumerable<T> (and also works for non-generic IEnumerable), and like of most of LINQ it uses deferred execution, that is, only converts as many items as are retrieved. Read more about it here: codeblog.jonskeet.uk/2011/01/13/…

Related Questions

Sponsored Content

20 Answered Questions

15 Answered Questions

[SOLVED] How to clone or copy a list?

44 Answered Questions

[SOLVED] How to make a flat list out of list of lists

6 Answered Questions

[SOLVED] Python class inherits object

26 Answered Questions

[SOLVED] Why not inherit from List<T>?

28 Answered Questions

[SOLVED] Finding the index of an item given a list containing it in Python

  • 2008-10-07 01:39:38
  • Eugene M
  • 3400621 View
  • 2802 Score
  • 28 Answer
  • Tags:   python list indexing

28 Answered Questions

[SOLVED] How do I check if a list is empty?

  • 2008-09-10 06:20:11
  • Ray Vega
  • 2410933 View
  • 3235 Score
  • 28 Answer
  • Tags:   python list

25 Answered Questions

[SOLVED] How do I concatenate two lists in Python?

5 Answered Questions

[SOLVED] Is there a reason for C#'s reuse of the variable in a foreach?

5 Answered Questions

[SOLVED] Try-catch speeding up my code?

Sponsored Content