简体   繁体   中英

TypeCast List<T> from TempData

I am trying to create a single MVC view to display a "Details" page for my search results, which can be of many different types (Applications, People, Computers, Licenses, etc etc)...

Given that all of these different types do NOT have the same object properties, or even the same basic properties, what I've decided to do to handle this is to pass along the list of results on the Search view, to the Details controller.

However, I am having an issue reading that information back within the controller... here's the code (partial) I have so far:

public ActionResult Details(int index)
    {
        List<object> SearchResults = TempData.ContainsKey("SearchItems") ? TempData["SearchItems"] as List<object> : null;
        if(SearchResults == null)
        {
            //go to error page.
            ViewBag.ErrorDescription = "Oups! Something went wrong trying to load the profile information. If you continue to see this error message, please contact the system administrator with the details below.";
            ViewBag.ErrorMessage = "An internal error occurred: TempData object key not found.";
            return View("Error");
        }

        if(SearchResults.Count == 0)
        {
            //go to error page.
            ViewBag.ErrorDescription = "Oups! Something went wrong trying to load the profile information. If you continue to see this error message, please contact the system administrator with the details below.";
            ViewBag.ErrorMessage = "An internal error occurred: TempData object contains no elements.";
            return View("Error");
        }

        //I also check if the index is out of range and stuff... 

        object TypeUse = SearchResults[0];

         //case statement and other actions are here...

    }

So far I can read the list by looking up the TempData[SearchItems] in the debugger and it shows me the correct information, BUT, for some reason as soon as I try to cast to List<object> , the SearchResults becomes null.

As you can see by the code above, the logic I follow is:

  1. check if the list exists;
  2. check if it's empty;
  3. other checks; and
  4. ONLY THEN, typecast it to it's real type via the first element in the list...

From there I would display the proper information for this type of object in the view...

So my question two fold:

  1. Is my logic sound in doing this in this order?
  2. Is there another way/standard way to do this?

You cannot cast a List<T> to a List<object> (unless T is object ). You could cast to an IEnumerable<object> and change your "first" object extraction:

IEnumerable<object> SearchResults = 
    TempData.ContainsKey("SearchItems") ? 
        TempData["SearchItems"] as IEnumerable<object> : 
        null;

...

object TypeUse = SearchResults.First();

This is due to co variance and contra variance

Say Cat and Dog both inherit from Animal .

You might expect to be able to cast a List<Cat> as a List<Animal> eg

List<Cat> cats = new List<Cat>();
cats.Add(new Cat());
List<Animal> animals = (List<Animal>)cats;

Animal first = animals[0];

Now whilst that all looks OK, this code won't actually work , if this behaviour was actually allowed then how could you cope with

animals.Add(new Dog());

Dog is not a valid type to be stored into a List<Cat> .

As you want to pull out a collection of base types you can use IEnumerable<Animal> .

IEnumerable<Animal> animals = (IEnumerable<Animal>)cats;
Animal first = cats.First(); // using Linq;

Be warned, for similar reasons you cannot then directly cast back to IEnumerable<Cat> as not every Animal is a Cat . You can use the Linq extensions methods OfType<Cat>() or Cast<Cat>() to do this.

So in your case you will need SearchResults to be of type IEnumerable<object> or even a base interface/class that all of your searchable types inherit from allowing you to utilize any common properties in your logic.

FollowUp

If you are using .Net 4.5 you can make use of IReadonlyList<T> instead of IEnumerable<T> . This provides the additional advantage of still providing the count and item indexing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM