12

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

    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>

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

4

4 回答 4

7

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

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

更新

我想我以前错了。这应该有效。也许问题出在视图中。您可以发布更多代码吗?尤其是 View 及其构造函数。

更新第二个:

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

但我也错误地认为你正在尝试做的事情会奏效。不幸的是,它不会。问题是您正在使用ViewPage<TModel>,它在ViewDataDictionary<TModel>内部使用 a 。因为它们需要强类型,所以您将无法对它们使用动态对象。内部结构只是在内部不使用动态,并且将动态指定为类型失败。

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

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

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

于 2009-07-24T17:22:50.707 回答
7

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

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

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

编辑:我自己刚刚学到了更多关于动力学的知识,我想也许你需要创建自己的动态对象类,它继承自DynamicObject。您将希望在该类中有一个私有字典,然后覆盖TrySetMemberand TryGetMember

编辑旁白:我认为强类型 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 的博客文章,可能会对您有所帮助。看起来这就是你要找的东西。缺少方法和 C# 4 的乐趣

于 2009-07-24T17:41:02.447 回答
1

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

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

于 2011-03-31T15:35:24.850 回答
1

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

于 2011-04-14T23:40:26.250 回答