我可以为MVC的HTML助手使用LambdaExpression类型吗?

时间:2017-02-14 15:49:14

标签: asp.net-mvc lambda expression html-helper

我正在尝试使用反射来自动生成视图。 public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapMvcAttributeRoutes();// New feature routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } 以及其他一些帮助者从Html.DisplayFor获取Expression<Func<,>>。看起来像我能够手动生成我自己的lambda,然后将其传入,但它会抛出此错误:

  

方法的类型参数&#39; DisplayExtensions.DisplayFor&lt; TModel,TValue&gt;(HtmlHelper&lt; TModel&gt;,Expression&lt; Func&lt; TModel,TValue&gt;&gt;)&#39;无法从使用中推断出来。尝试明确指定类型参数。

这是我的标记:

LambdaExpression

我很确定发生了什么<tr> @foreach (var pi in Model.GetType().GetProperties()) { <td> @Html.DisplayFor(ExpressionHelpers.GetPropertyGetterLambda(pi)) </td> } </tr> 需要泛型类型参数来推断.DisplayFor的类型,但我使用隐藏类型的Func<TModel, TValue>

似乎做我想要的唯一方法是构建/编译一个实际使用类型安全参数调用LambdaExpression的表达式,但这似乎过于复杂。

是否有其他方法可以实现我的目标,或者我最好只将结果直接输出到HTML而不是调用助手?

修改:根据请求,这里是.DisplayFor的代码:

GetPropertyGetterLambda

1 个答案:

答案 0 :(得分:0)

首先我推荐另一个解决方案。将您的for循环更改为DisplayForModel来电:

@Html.DisplayForModel()

这将在内部使用DisplayFor呈现所有属性。您可以通过修改Object.cshtml文件夹中的DisplayTemplates(在您正在使用的Views文件夹中,或在Shared文件夹中全局应用)来修改此项。< / p>

如果这还不够,或者你真的想使用LambdaExpression,这里有另一种选择。它需要您添加DisplayFor<TModel>(LambdaExpression expression)扩展方法。它会是这样的(请注意,我实际上并没有对此进行过测试,但这很接近所需要的):

    public static IHtmlString DisplayFor<TModel>(this HtmlHelper<TModel> helper, LambdaExpression expression)
    {
        var wrapperClass = typeof(DisplayExtensions);
        ///find matching DisplayFor<TModel, TProperty> method
        var matchingMethod = wrapperClass.GetMethods()
            .Single( c => c.IsStatic 
                && c.Name == "DisplayFor"
                && c.GetGenericArguments(  ).Count() == 2 
                && c.GetParameters(  ).Count() == 2 //overloads don't have same # of parameters. This should be sufficient.
                ).MakeGenericMethod( typeof(TModel), expression.ReturnType ); //Make generic type from the TModel and the Return Type

        //invoke the method. The result is a IHtmlString already, so just cast.
        return (IHtmlString) matchingMethod.Invoke( null, new Object[] { helper, expression } );
    }