如您所知,我们可以在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}}
请您解释一下,如何以及为什么内联辅助方法在运行时评估类型?
答案 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。