Razor中的动态匿名类型导致RuntimeBinderException

Jar*_*ttV 155 dynamic anonymous-types razor asp.net-mvc-3

我收到以下错误:

'object'不包含'RatingName'的定义

当您查看匿名动态类型时,它显然具有RatingName.

错误的屏幕截图

我意识到我可以用元组做到这一点,但我想理解为什么会出现错误信息.

Ada*_*abi 238

在我看来,具有内部属性的匿名类型是一个糟糕的.NET框架设计决策.

这是一个快速而好的扩展来解决这个问题,即通过立即将匿名对象转换为ExpandoObject.

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary =  new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}
Run Code Online (Sandbox Code Playgroud)

它非常容易使用:

return View("ViewName", someLinq.Select(new { x=1, y=2}.ToExpando());
Run Code Online (Sandbox Code Playgroud)

当然在你看来:

@foreach (var item in Model) {
     <div>x = @item.x, y = @item.y</div>
}
Run Code Online (Sandbox Code Playgroud)

  • 与简单地制作强类型支持模型相比,这方面的表现如何? (3认同)
  • +1我特意寻找HtmlHelper.AnonymousObjectToHtmlAttributes我知道这绝对必须已经完成并且不想用类似的手动代码重新发明轮子. (2认同)

Jar*_*ttV 50

我在相关问题中找到了答案.答案在David Ebbo的博客文章中指定,将匿名对象传递给MVC视图并使用动态访问它们

这样做的原因是匿名类型在内部控制器中传递,因此只能从声明它的程序集中访问它.由于视图是单独编译的,因此动态绑定器会抱怨它无法遍历该程序集边界.

但是如果你考虑一下,动态绑定器的这种限制实际上是非常人为的,因为如果你使用私有反射,没有什么能阻止你访问那些内部成员(是的,它甚至可以在中等信任中工作).因此,默认的动态绑定程序不会强制执行C#编译规则(您无法访问内部成员),而不是让您执行CLR运行时允许的操作.

  • @DotNetWise:它解释了错误发生的原因,这就是问题所在.你也得到了我的upvote提供了一个很好的解决方法:) (4认同)

ale*_*xey 24

使用ToExpando方法是最好的解决方案.

这是不需要System.Web程序集的版本:

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
    {
        var obj = propertyDescriptor.GetValue(anonymousObject);
        expando.Add(propertyDescriptor.Name, obj);
    }

    return (ExpandoObject)expando;
}
Run Code Online (Sandbox Code Playgroud)


Sim*_*ver 16

而不是从匿名类型创建模型,然后尝试将匿名对象转换为ExpandoObject这样的...

var model = new 
{
    Profile = profile,
    Foo = foo
};

return View(model.ToExpando());  // not a framework method (see other answers)
Run Code Online (Sandbox Code Playgroud)

你可以直接创建ExpandoObject:

dynamic model = new ExpandoObject();
model.Profile = profile;
model.Foo = foo;

return View(model);
Run Code Online (Sandbox Code Playgroud)

然后在您的视图中将模型类型设置为动态@model dynamic,您可以直接访问属性:

@Model.Profile.Name
@Model.Foo
Run Code Online (Sandbox Code Playgroud)

我通常会为大多数视图推荐强类型视图模型,但有时这种灵活性很方便.

  • 顺便说一句,您不必添加@model动态,因为它是默认值 (2认同)

jbt*_*ule 5

您可以使用框架即兴接口界面中包装匿名类型.

您只需返回一个IEnumerable<IMadeUpInterface>并且在Linq使用结束时使用.AllActLike<IMadeUpInterface>();它,因为它使用DLR调用匿名属性,并使用声明匿名类型的程序集的上下文.