来自 TempData 的 TypeCast 列表 <T>
TypeCast List<T> from TempData
我正在尝试创建一个 MVC 视图来为我的搜索结果显示一个 "Details" 页面,它可以是许多不同的类型(应用程序、人员、计算机、许可证等)...
考虑到所有这些不同的类型都没有相同的对象属性,甚至没有相同的基本属性,我决定处理这个问题的方法是在搜索视图中传递结果列表,到细节控制器。
但是,我在控制器中读取该信息时遇到问题...这是我目前拥有的代码(部分):
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...
}
到目前为止,我可以通过在调试器中查找 TempData[SearchItems]
来阅读列表,它向我显示了正确的信息,但是,出于某种原因,一旦我尝试转换为 List<object>
, SearchResults
变为空。
从上面的代码可以看出,我遵循的逻辑是:
- 检查列表是否存在;
- 检查是否为空;
- 其他检查;和
- 然后,通过列表中的第一个元素将其类型转换为真实类型...
从那里我会在视图中显示此类对象的正确信息...
所以我的问题有两个:
- 按这个顺序我的逻辑合理吗?
- 还有其他 way/standard 方法吗?
You cannot cast a List<T>
to a List<object>
(除非T
是object
)。您可以转换为 IEnumerable<object>
并更改 "first" 对象提取:
IEnumerable<object> SearchResults =
TempData.ContainsKey("SearchItems") ?
TempData["SearchItems"] as IEnumerable<object> :
null;
...
object TypeUse = SearchResults.First();
这是由于 co variance and contra variance
说 Cat
和 Dog
都继承自 Animal
。
您可能希望能够将 List<Cat>
转换为 List<Animal>
,例如
List<Cat> cats = new List<Cat>();
cats.Add(new Cat());
List<Animal> animals = (List<Animal>)cats;
Animal first = animals[0];
现在虽然一切看起来都不错,但这段代码实际上不会工作,如果这种行为实际上被允许那么你如何应对
animals.Add(new Dog());
Dog
不是要存储到 List<Cat>
.
中的有效类型
如果您想提取基类型的集合,您可以使用 IEnumerable<Animal>
。
IEnumerable<Animal> animals = (IEnumerable<Animal>)cats;
Animal first = cats.First(); // using Linq;
请注意,出于类似的原因,您不能直接转换回 IEnumerable<Cat>
,因为并非每个 Animal
都是 Cat
。您可以使用 Linq 扩展方法 OfType<Cat>()
或 Cast<Cat>()
来执行此操作。
因此,在您的情况下,您需要 SearchResults
为 IEnumerable<object>
类型或什至是一个基础 interface/class,您的所有可搜索类型都继承自该类型,从而允许您使用任何公共属性按照你的逻辑。
跟进
如果您使用的是 .Net 4.5,则可以使用 IReadonlyList<T>
而不是 IEnumerable<T>
。这提供了仍然提供计数和项目索引的额外优势。
我正在尝试创建一个 MVC 视图来为我的搜索结果显示一个 "Details" 页面,它可以是许多不同的类型(应用程序、人员、计算机、许可证等)...
考虑到所有这些不同的类型都没有相同的对象属性,甚至没有相同的基本属性,我决定处理这个问题的方法是在搜索视图中传递结果列表,到细节控制器。
但是,我在控制器中读取该信息时遇到问题...这是我目前拥有的代码(部分):
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...
}
到目前为止,我可以通过在调试器中查找 TempData[SearchItems]
来阅读列表,它向我显示了正确的信息,但是,出于某种原因,一旦我尝试转换为 List<object>
, SearchResults
变为空。
从上面的代码可以看出,我遵循的逻辑是:
- 检查列表是否存在;
- 检查是否为空;
- 其他检查;和
- 然后,通过列表中的第一个元素将其类型转换为真实类型...
从那里我会在视图中显示此类对象的正确信息...
所以我的问题有两个:
- 按这个顺序我的逻辑合理吗?
- 还有其他 way/standard 方法吗?
You cannot cast a List<T>
to a List<object>
(除非T
是object
)。您可以转换为 IEnumerable<object>
并更改 "first" 对象提取:
IEnumerable<object> SearchResults =
TempData.ContainsKey("SearchItems") ?
TempData["SearchItems"] as IEnumerable<object> :
null;
...
object TypeUse = SearchResults.First();
这是由于 co variance and contra variance
说 Cat
和 Dog
都继承自 Animal
。
您可能希望能够将 List<Cat>
转换为 List<Animal>
,例如
List<Cat> cats = new List<Cat>();
cats.Add(new Cat());
List<Animal> animals = (List<Animal>)cats;
Animal first = animals[0];
现在虽然一切看起来都不错,但这段代码实际上不会工作,如果这种行为实际上被允许那么你如何应对
animals.Add(new Dog());
Dog
不是要存储到 List<Cat>
.
如果您想提取基类型的集合,您可以使用 IEnumerable<Animal>
。
IEnumerable<Animal> animals = (IEnumerable<Animal>)cats;
Animal first = cats.First(); // using Linq;
请注意,出于类似的原因,您不能直接转换回 IEnumerable<Cat>
,因为并非每个 Animal
都是 Cat
。您可以使用 Linq 扩展方法 OfType<Cat>()
或 Cast<Cat>()
来执行此操作。
因此,在您的情况下,您需要 SearchResults
为 IEnumerable<object>
类型或什至是一个基础 interface/class,您的所有可搜索类型都继承自该类型,从而允许您使用任何公共属性按照你的逻辑。
跟进
如果您使用的是 .Net 4.5,则可以使用 IReadonlyList<T>
而不是 IEnumerable<T>
。这提供了仍然提供计数和项目索引的额外优势。