1

I am getting a runtime exception and can't figure out why

Unable to cast object of type 'System.Collections.Generic.List`1[Foo.ElementNameViewModel]' to type 'Foo.ElementNameList'.

The classes I have are

ElementNameList - a list of a particular type

namespace Foo
{
    public class ElementNameList : List<ElementNameViewModel> {}
}

ElementNameViewModel - an item to be in a list

namespace Foo
{
    public class ElementNameViewModel
    {
        public string Symbol { get; set; }
        public string Name { get; set; }
    }
}

and the exception occurs in a controller at

var elements = (ElementNameList) db.Elements
            .Select(c => new ElementNameViewModel
            {
                Symbol = c.Symbol,
                Name = c.Name
            })
            .OrderBy(e => e.Symbol)
            .ToList();

Not sure how I should refactor the elements list if subclassing List is not done.

maccettura
  • 9,653
  • 3
  • 20
  • 28
Richard
  • 21,809
  • 3
  • 20
  • 31
  • 4
    Usually inheriting `List` is a bad idea, what are you trying to accomplish here? Why not just have a `List`? – maccettura Oct 03 '18 at 19:47
  • Not only is it generally considered a very bad idea to extend list, you're reasoning about inheritance *backwards*. Your list is a *more specialized kind of list*; you can't use a *less specialized* list in a context where a *specialized list* is required, the same way that you can't use a Fruit in a context where an Apple is expected. The Fruit might be an orange! – Eric Lippert Oct 03 '18 at 20:27
  • 1
    See https://stackoverflow.com/questions/21692193/why-not-inherit-from-listt/21694054#21694054 for details. – Eric Lippert Oct 03 '18 at 20:28

3 Answers3

2

ToList() returns a real System.Collections.Generic.List instance, not your ElementNameList.

You can cast ElementNameList to IList<ElementNameViewModel> or to List<ElementNameViewModel>, but not the other way.

The reason is because your ElementNameList may have a property that the List<ElementNameViewModel> doesn't have. What would happen if you try to access that property after the cast?

public class ElementNameList : List<ElementNameViewModel> {
    public int X { get; set; }
}

var list = new List<ElementNameViewModel>();
ElementNameList elementList = (ElementNameList) list;
int x = elementList.X; // List<ElementNameViewModel> doesn't have 'X' property, what would happen here?
lmcarreiro
  • 4,176
  • 1
  • 28
  • 53
  • 2
    All great answers and clarified the situation. I decided to not subclass and have coded `List` (as reinforced by @maccettura comment) in places I was going to have `ElementNameList` – Richard Oct 04 '18 at 01:13
1

As said in other answers like Optimistic Peachs' and lmcarreiro's one, the ToList() LINQ extension method returns an basic List<T> object, not an object of your customized ElementNameList class.

To solve your immediate problem, I would write it as:

var qry = db.Elements
            .Select(c => new ElementNameViewModel
            {
                Symbol = c.Symbol,
                Name = c.Name
            })
            .OrderBy(e => e.Symbol);
var elements = new ElementNameList();
elements.AddRange(qry);

I don't have an Visual Studio at hand now to see if I need to use qry.ToList() in the AddRange call, but I believe that is enough.

By the way, why you had to subclass the list?

Fabricio Araujo
  • 3,868
  • 1
  • 25
  • 40
0

Casting to inherited/derived members only goes one way... And that is up the derived hierarchy.

For example:

class Animal{
    int number_of_legs;
}
class Cat: Animal{
    string current_sound = "meow";
}

If you create an animal (Which should really be abstract in this case, but ignore that) and want to convert it into a cat, and assign that to a variable mycat then what would the value stored in mycat.current_sound be? It cannot be inferred because Cat has all the members that Animal has and more, so the conversion from Cat to Animal would make you lose the members that Cat has and only be left with the members from Animal (Unless you cast it again but that's irrelevant...)

P.S. I've recently been coding in a different language so pardon my naming of variables and format of my code

Optimistic Peach
  • 2,689
  • 1
  • 13
  • 25