1

I have a class that extends List:

public class MyObjectList : List<MyObject>
{
    ...
}

Currently, there is a LINQ statement that groups by a key value:

MyObjectList objects = new MyObjectList(); //initializes and loads list

var objectsByKey = objects.GroupBy(obj => obj.MyKey)
                          .Select(objs => new {MyKey = objs.Key, MyObjs = objs.ToList()})
                          .ToList();

In the output, MyObjs is of type List< MyObject>, and it lists the correctly grouped objects.

When I try to cast it as MyObjectList, MyObjs ends up being null.

var objectsByKey = objects.GroupBy(obj => obj.MyKey)
                          .Select(objs => new {MyKey = objs.Key, MyObjs = objs.ToList() as MyObjectList})
                          .ToList();

How can I get MyObjs to be of type MyObjectList, with the correclty grouped objects?

jkh
  • 3,618
  • 8
  • 38
  • 66
  • 4
    Deriving your class from `List` is a bad practice for exactly this reason, among others. If you need your class to behave like a list, implement `IList`. – Daniel Mann Jul 11 '14 at 17:55
  • 1
    Lengthy discussion of @DanielMann's point found here: http://stackoverflow.com/questions/21692193/why-not-inherit-from-listt – Ocelot20 Jul 11 '14 at 18:15

2 Answers2

1

In your MyObjectList class, provide a constructor like so:

public class MyObjectList : List<MyObject>
{
    public MyObjectList(IEnumerable<MyObject> list)
        :base(list)
    {   
    }
}

Then, when selecting out your objects, do it like this:

var objectsByKey = objects.GroupBy(obj => obj.MyKey)
                          .Select(objs => new {MyKey = objs.Key, MyObjs = new MyObjectList(objs)})
                          .ToList();
pixelTitan
  • 455
  • 3
  • 10
  • lol, I just added the same answer. Almost word for word. I'll delete mine since you had yours posted first. I suppose this means I should give you a +1. – J.H. Jul 11 '14 at 17:58
0

Enumerable.ToList (the extension method that you are using) does not know about your custom list type. Casting will not convert it.

You need to instantiate and fill the list yourself. There are at least two ways of doing it:

  1. Constructor

    public MyObjectList(IEnumerable<MyObject> collection) : base(collection) {}
    

    You'd have to replace the objs.ToList() call with new MyObjectList(objs)

  2. Extension method

    public static class MyObjectListExtensions
    {
        public static MyObjectList ToList(this IEnumerable<MyObject> collection)
        {
            //You could also call the constructor described above
            var list = new MyObjectList();
            list.AddRange(collection);
            return list;
        }
    }
    

    With this, you don't have to change your code, as long as you include the namespace of MyObjectListExtensions in your file. Why? Because being non-generic, MyObjectListExtensions.ToList takes precedence over Enumerable.ToList.

    If you don't want MyObjectList to be instantiated always, you could use a different name.

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154