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:
So my question two fold:
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.