动态类型的ViewPage

时间:2009-07-24 17:21:17

标签: asp.net-mvc dynamic c#-4.0 typing viewpage

这可能吗?这是我正在尝试的:

    public ActionResult Index()
    {
        dynamic p = new { Name = "Test", Phone = "111-2222" };
        return View(p);
    }

然后我的视图继承自System.Web.Mvc.ViewPage<dynamic>并尝试打印出Model.Name。

我收到错误:'&lt;&gt; f__AnonymousType1.Name'由于其保护级别而无法访问

所以基本上,我正在尝试做的是不可能的?为什么或为什么不呢?

更新:这是我的观点

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ...>
    <%=Model.Name%>
    <%=Model.Phone%>
</asp:Content>

View构造函数内置于框架中。

4 个答案:

答案 0 :(得分:7)

方法无法返回匿名类型;它们仅在定义它们的方法范围内有效。

您应该使用之前定义的Model类并将其传递给View。传递没有定义每个字段的Model类没有任何问题。

<强>更新

我认为我之前错了。这应该工作。也许问题出在View中。你能发布更多代码吗?特别是View及其构造函数。

更新第二个:

好吧,我把匿名类型传递给另一个方法用作动态变量是错误的 - 可以这样做。

但我相信你想要做的事情会起作用我也错了。不幸的是,它不会。问题是您使用的是ViewPage<TModel>,它在内部使用ViewDataDictionary<TModel>。因为它们需要强类型,所以您将无法使用动态对象。内部结构在内部不使用动态,并且在类型失败时指定dynamic。

需要的是DynamicViewPage类和相应的DynamicViewDataDictionary类接受object并将其作为动态存储在内部。然后,您可以使用匿名类型并将其传递给您的视图。

那就是说,你什么都得不到。你可以像你所做的那样指定你的意见(即<%=Model.Name%>),但你不会从强类型中受益。没有intellisense,也没有类型安全。你也可以使用@Dennis Palmer建议的无类型ViewDataDictionary

这是一个有趣的(并且,不幸的是,我吸收)思想实验,但我认为,最终,它不会发生。声明一个公共类型并将其传递给您的视图,或使用无类型字典。

答案 1 :(得分:7)

您希望在此处使用动态类型有什么好处?

使用ViewData字典是一种非常简单的方法,可以将任意对象/项添加到视图输出中。

您不需要反射来获取视图中的属性名称。只需使用ViewData.Keys来获取名称集合。

编辑:我刚刚学习了一些关于动态的知识,我想也许你需要创建一个继承自DynamicObject的动态对象类。您需要在该课程中拥有私人字典,然后覆盖TrySetMemberTryGetMember

编辑旁白:我认为强类型ViewModel的一个优点是您可以将其作为POST Action方法中的参数接受。 MVC框架将处理模型绑定,而在action方法中,您只需要一个ViewModel类的实例。即使他们有效,我也不认为你会拥有动态的优势。

编辑结果好吧,我尝试使用从DynamicObject派生的类,但VS2010在尝试渲染视图时崩溃。我没有任何异常,只是一个硬崩溃和Visual Studio重新启动。这是我提出的导致崩溃的代码。

自定义动态类:

public class DynViewModel : DynamicObject
{
    private Dictionary<string, object> ViewDataBag;
    public DynViewModel()
    {
        this.ViewDataBag = new Dictionary<string, object>();
    }
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this.ViewDataBag[binder.Name] = value;
        return true;
    }
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = this.ViewDataBag[binder.Name];
        return true;
    }
}

在控制器中:

public ActionResult DynamicView()
{
    dynamic p = new DynamicViewModel.Models.DynViewModel();
    p.Name = "Test";
    p.Phone = "111-2222";

    return View(p);
}

我的观点基本上与问题中列出的内容相同:

<p>Name: <%=Model.Name %></p>
<p>Phone: <%=Model.Phone %></p>

我的结论:这可能会有效,但在VS2010的Beta 1中,我无法弄清楚为什么我的代码会导致Visual Studio崩溃。我将在VS2010 Beta 2中再次尝试它,因为它是一个学习动态的有趣练习。但是,即使这样可行,我仍然看不到使用ViewData字典的任何优势。

Phil Haack救援!以下是Phil Haack的一篇博文,可能会帮助你。它看起来像你在寻找。 Fun With Method Missing and C# 4

答案 2 :(得分:1)

此处的实际错误(<>f__AnonymousType1.Name' is inaccessible due to its protection level)是使用匿名类型的结果。匿名类型是隐式internal(至少在C#中),因此只能从同一个程序集中正常访问它们。由于您的视图在运行时被编译为单独的程序集,因此无法访问internal匿名类型。

解决方案是将具体/命名类作为模型传递给您的视图。如果您愿意,视图本身仍然可以使用dynamic

答案 3 :(得分:1)

在.NET 4.0上,匿名类型可以很容易地转换为ExpandoObjects,因此所有问题都可以通过转换本身的开销来解决。 查看here