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

How and why inline helper methods evaluating types at runtime?

如您所知,我们可以在 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)

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

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

public dynamic ViewBag{get;}

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

换句话说,任何基于动态类型的表达式在 运行 time.Any 成员集上编译或从 ViewBag 中读出总是被编译器接受,但在执行之前不会实际计算。

区别仅在于用于调用助手的 语法 ListArrayItemsInline 是普通方法,而 ListArrayItemsExternal 是扩展方法。如果您尝试在不转换参数的情况下将 ListArrayItemsExternal 作为扩展方法调用,则编译器会给出此错误消息:

CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'ListArrayItemsExternal' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

错误消息建议了两个解决错误的选项:

选项 1。 转换动态参数:

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

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

MyHelpers.ListArrayItemsExternal(Html, ViewBag.Fruits)

第二个选项表明类型 可以 在 运行 时间解析外部辅助方法。您只需要使用正确的语法即可。

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