这是我的 Controller 的代码:
IQueryable<Foo> foos = dbContext.Foos.Where(...);
return View(foos);
这个 Razor 代码(cshtml)有效好 :
@model IQueryable<Foo>
@{
IQueryable<Foo> foos = Model;
var projected = foos.Select(e => new
{
fooId = e.FooId,
bar = new
{
barId = e.Foo.BarId
}
}).ToList();
}
@foreach (var x in projected)
{
<span>@x.fooId</span><br />
}
但是这个 Razor 代码(cshtml)不起作用,几乎是一样的!:
@model IQueryable<Foo>
@{
IQueryable<Foo> foos = Model;
var projected = foos.Selected(Foo.Projection()).ToList()
}
@foreach (var x in projected)
{
<span>@x.fooId</span><br />
}
Foo.Projection()
是一个我经常重复使用的静态方法: public static Expression<Func<Foo, dynamic>> Projection()
{
return e => new
{
fooId = e.FooId,
bar = new
{
barId = e.Foo.BarId
}
}
}
我遇到了那个著名的错误:
'object' does not contain definition for 'fooId'
,在这里讨论:MVC Razor dynamic model, 'object' does not contain definition for 'PropertyName' - 但这些答案都没有帮助我。接受的答案是:“现在 MVC 3 直接支持动态,不再需要下面的技术”,所以我也尝试返回预计的
List<dynamic>
到 View (“准备使用,不需要投影”),它也没有工作(得到同样的错误)。这是该尝试的代码:Controller 代码:
List<dynamic> foos = dbContext.Foos.Select(Foo.Projection()).ToList();
return View(foos);
查看代码:
@model dynamic
etc.
编辑:使用调试器,我可以检查(在抛出异常之后)该项目确实有
"a definition for..."
(在示例代码中,该项目是 x
,但这里是 lot
)最佳答案
当您使用 dynamic
您指示编译器使用反射来调用方法和访问属性。在您的情况下,您以这种方式访问的对象是匿名类型,匿名类型是 internal
到创建它们的程序集中。
为 Razor View 生成的代码位于单独的程序集中,尝试反射(reflect)在 Controller 中创建的匿名类型将失败。调试器不受此限制的影响,因此当反射失败并引发异常时,您仍然可以在调试器中检查匿名类型的属性。
这也解释了为什么您的代码在 Razor View 中创建匿名类型时有效。然后你使用 dynamic
生成的代码能够反射(reflect)匿名类型,因为它是在同一个程序集中声明的。
本质上,在 MVC Razor 中,当在 Controller 中声明匿名类型时,您无法在 View 中使用它们。您对 dynamic
的使用通过生成一个难以理解的运行时错误来隐藏这个潜在的问题。
要解决您的问题,您可以创建特定的公共(public)类型而不是使用内部匿名类型,或者您可以 convert the anonymous type to an ExpandoObject
在 Controller 中。
关于asp.net-mvc - List<dynamic> 的奇怪 Razor 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28706578/