动态类型ViewPage

问题描述:

这可能吗?这里就是我想:动态类型ViewPage

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

然后我的观点从System.Web.Mvc.ViewPage<dynamic>继承并试图打印出Model.Name。

我发现了一个错误:<> 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> 

观构造函数是内置的框架。

+1

你能发表更多的代码吗?我特别想看到构造函数来查看 – Randolpho 2009-07-24 17:36:14

+1

查看我的最新更新,并链接到Phil Haack的博客文章。 – CoderDennis 2009-08-28 19:51:00

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

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

更新

我想我是错了。这应该工作。或许这个问题在视图内。你能发布更多的代码吗?特别是视图及其构造函数。

更新二:

好吧,我错了关于通过一个匿名类型的另一种方法用作动态变量 - 是可以做到的。

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

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

这就是说,你不会获得任何东西。您可以像您所做的那样指定您的视图(即<%=Model.Name%>),但您不会从强大的打字中受益。没有智能感知,也没有类型安全。正如@Dennis Palmer所建议的那样,你也可以使用无类型的ViewDataDictionary

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

+1

但我可以通过反射访问对象的成员,这就是为什么我认为动态输入可能有效。 – 2009-07-24 17:25:42

你希望从这里使用动态类型获得什么好处?

使用ViewData字典是向您的视图输出添加任意对象/项目的一种非常简单的方法。

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

编辑:我刚刚了解了一些关于动力学的内容,我想也许您需要创建自己的动态对象类,它继承自DynamicObject。您需要在该课程中使用专用字典,然后覆盖TrySetMemberTryGetMember

编辑另外:我认为强类型ViewModel的一个优点是你可以接受它作为POST Action方法中的一个参数。 MVC框架将处理模型绑定,并且在操作方法中,您只需拥有一个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词典的优势。

菲尔·哈克去救援!菲尔哈克的博客文章可能会帮助你。它看起来就是你在找的东西。 Fun With Method Missing and C# 4

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

解决方案是将混凝土/命名类作为模型传递给您的视图。如果需要,视图本身仍然可以使用dynamic

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