内联辅助方法如何以及为什么在运行时评估类型?

时间:2015-03-08 15:40:17

标签: c# .net asp.net-mvc razor

如您所知,我们可以在ASP.NET MVC中创建两种类型的 Helper方法

  • 内联辅助方法
  • 外部帮助方法

现在,假设我使用ViewBag对象将数据从控制器传递到视图。像那样:

ViewBag.Fruits = new string[] {"Apple", "Orange", "Pear"};

我在视图中定义了这样的内联辅助方法

@helper ListArrayItemsInline(string[] items)
{
    ...
}

这是一个外部辅助方法,它将字符串数组作为输入:

public static MvcHtmlString ListArrayItemsExternal(this HtmlHelper html, string[] list)
{
    ...
}

差异就是,如果我想使用外部的ViewBag.Fruits,我必须将string[]强制转换为// external one, we must cast @Html.ListArrayItemsExternal((string[])ViewBag.Fruits) // internal one, works just fine @ListArrayItemsInline(ViewBag.Fruits) 。是的,一切都在这里。但是,内联的情况并非如此。正如我所见,它在运行时评估类型。

{{1}}

请您解释一下,如何以及为什么内联辅助方法在运行时评估类型?

2 个答案:

答案 0 :(得分:1)

ViewBag属性提供了一种将数据传递给视图的灵活方式.ViewBag的属性定义为动态类型

public dynamic ViewBag{get;}

当.NET编译器遇到动态类型时,它会发出一个特殊的代码块,而不是简单地评估表达式。这种特殊的代码块将表达式传递给动态语言运行时(DLR)进行运行时评估。

换句话说,任何基于动态类型的表达式都是在运行时编译的。编译器始终接受任何成员设置或读取ViewBag,但在执行之前不会实际评估。

答案 1 :(得分:1)

区别仅在于您用于调用帮助程序的语法ListArrayItemsInline是一种常规方法,但ListArrayItemsExternal是一种扩展方法。如果您尝试在不转换参数的情况下调用ListArrayItemsExternal作为扩展方法,则编译器会向您显示以下错误消息:

  

CS1973:' System.Web.Mvc.HtmlHelper'没有名为' ListArrayItemsExternal'的适用方法但似乎有一个名称的扩展方法。无法动态分派扩展方法。考虑转换动态参数或调用扩展方法而不使用扩展方法语法。

错误消息提示了解决错误的两个选项:

选项1。投射动态参数:

@Html.ListArrayItemsExternal((string[])ViewBag.Fruits) 

选项2。使用常规方法语法调用ListArrayItemsExternal,在这种情况下,您不必转换动态参数:

MyHelpers.ListArrayItemsExternal(Html, ViewBag.Fruits)

第二个选项演示了在运行时可以为外部辅助方法解析类型 。您只需使用正确的语法。

至于为什么扩展方法无法动态调度,请查看this answer by Eric Lippert