0

I'm trying to cast a List to my custom list which is ProjectList

IList<Project> projects = cm.GetOrAdd("projectList", () => (ProjectList)ProjectService.GetAllProjects().ToList(), new CacheItemPolicy(5));

ProjectList contains only:

public class ProjectList : List<Project>
{
    public override string ToString()
    {
        return string.Format("Projects: {0}", this.Count());
    }
}

However it's giving a runtime error that it cant cast the object.

Error:

System.Collections.Generic.List`1[sidc.Framework.Data.Entities.Project] can't be converted to type sidc.Framework.Web.Helpers.ProjectList.

Am I overseeing something? I'm using the lambda because my cm (CacheManager) will evaluate the Func<> when the object is not in cache.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Martin
  • 397
  • 3
  • 16
  • `(ProjectList)ProjectService.GetAllProjects().ToList()` should be `(List)ProjectService.GetAllProjects().ToList()` – Davor Zlotrg Apr 20 '15 at 11:24
  • @DZL That wouldn't work either as you cannot cast `List` to `List`. – juharr Apr 20 '15 at 11:31
  • Can you be more specific about what is unclear to you? That cast is simply invalid. – usr Apr 20 '15 at 11:31
  • I agree, show your model, If `ProjectList` contains `List` you could use `ProjectService.GetAllProjects().ToList().SelectMany(pl => pl.Projects)` – Davor Zlotrg Apr 20 '15 at 11:34

2 Answers2

3

You can't downcast a List<T> to any type that inherits from List<T>, because the runtime can't fill in the blanks for you. It wouldn't know how to create a "Dog" from an "Animal". That's what the compiler tries to tell you.

Add a constructor that accepts an enumerable of Project, and populates itself with that list:

public class ProjectList : List<Project>
{
    public ProjectList() { }
    public ProjectList(IEnumerable<Project> projects)
        : this()
    {
        this.AddRange(projects);
    }

    public override string ToString()
    {
        return string.Format("Projects: {0}", this.Count());
    }
}

Then change your lambda from:

() => (ProjectList)ProjectService.GetAllProjects().ToList() 

To:

() => new ProjectList(ProjectService.GetAllProjects())

But by introducing a concrete type (ProjectList for List<Project>) you're pretty much annihilating the use of generics: not having to specify a type per record type. You probably don't need ProjectList at all.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • The only reason of ProjectList is to use the overide ToString method. – Martin Apr 20 '15 at 13:39
  • Depending on why you need that, you can solve it in a different way. – CodeCaster Apr 20 '15 at 13:40
  • Mu cachemanager accepts any type of object. I have a cache manager debug page that shows more info about the objects. That is where i use tostring as the debug page doest know anything about the objects – Martin Apr 20 '15 at 14:19
  • Debugging shouldn't be invasive. With some type checking and maybe some reflection you can easily print `List.Count = {0}`. – CodeCaster Apr 20 '15 at 14:25
  • I agree but some other cached objects are more complex. I may as well skip as it is really debug. – Martin Apr 20 '15 at 14:29
  • 1
    You still don't want to alter your code for debugging. See [Change “ToString” for a sealed class](http://stackoverflow.com/questions/2120998/change-tostring-for-a-sealed-class) for some hints. – CodeCaster Apr 20 '15 at 14:32
  • I'll look into it, looks (to me) more complex as I will have to evaluate each component in the cache, and also the ones I do not have in control (plugins). – Martin Apr 20 '15 at 16:13
0

This is just how inheritance works - you can cast ProjectList to List<Project>, but not the other way - List<Project> is not of type ProjectList

rasmeta
  • 465
  • 2
  • 12