Asp.net mvc 可以用Razor创建一个泛型@helper方法吗?

Asp.net mvc 可以用Razor创建一个泛型@helper方法吗?,asp.net-mvc,generics,asp.net-mvc-3,razor,Asp.net Mvc,Generics,Asp.net Mvc 3,Razor,我正在尝试在Razor中编写一个助手,如下所示: @helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class @helper DoSomething(表达式expr),其中T:class 不幸的是,解析器认为这是不可能的。您可以编写一个普通的HTML帮助程序 public static MvcHtmlString DoSomething<T, U>( th

我正在尝试在Razor中编写一个助手,如下所示:

@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
@helper DoSomething(表达式expr),其中T:class

不幸的是,解析器认为这是不可能的。您可以编写一个普通的HTML帮助程序

public static MvcHtmlString DoSomething<T, U>(
    this HtmlHelper htmlHelper, 
    Expression<Func<T, U>> expr
) where T : class
{
    ...
}

可以通过
@函数
语法在助手文件中实现,但是如果您想要所指的剃刀风格的可读性,您还需要调用常规助手来完成HTML调整和完成

请注意,助手文件中的函数是静态的,因此如果您打算使用其方法,则仍然需要从页面传入HtmlHelper实例

e、 g。 视图\MyView.cshtml:

@MyHelper.DoSomething(Html, m=>m.Property1)
@MyHelper.DoSomething(Html, m=>m.Property2)
@MyHelper.DoSomething(Html, m=>m.Property3)
App\u Code\MyHelper.cshtml:

@using System.Web.Mvc;
@using System.Web.Mvc.Html;
@using System.Linq.Expressions;
@functions
{
    public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
    {
        return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr));
    }
}
@helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage)
{
    <p>
        @label
        <br />
        @textbox
        @validationMessage
    </p>
}
...
@使用System.Web.Mvc;
@使用System.Web.Mvc.Html;
@使用System.Linq.Expressions;
@功能
{
公共静态HelperResult DoSomething(HtmlHelperHTML,表达式表达式表达式)
{
返回thingtodo(html.LabelFor(expr)、html.EditorFor(expr)、html.ValidationMessageFor(expr));
}
}
@helper ThingTodo(MvcHtmlString标签、MvcHtmlString文本框、MvcHtmlString验证消息)
{

@标签

@文本框 @验证消息

} ...
如果您的主要问题是使用lambda表达式获取绑定的name属性值类似于
@Html.TextBoxFor(x=>x.MyPoperty)
,并且如果您的组件具有非常复杂的Html标记并且应该在razor helper上实现,那么,为什么不创建
HtmlHelper
的扩展方法来解析绑定名称呢

namespace System.Web.Mvc
{
    public static class MyHelpers
    {
        public static string GetNameForBinding<TModel, TProperty>
           (this HtmlHelper<TModel> model, 
            Expression<Func<TModel, TProperty>> property)
        {
            return ExpressionHelper.GetExpressionText(property);
        }
    }
}

在所有情况下,
TModel
都将是相同的(为视图声明的模型),在我的情况下,
TValue
将是相同的,因此我能够声明表达式参数类型:

@helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) {
  <div class="form-group">
    @(Html.LabelFor(expression, new { @class = "control-label col-sm-6 text-right" }))
    <div class="col-sm-6">
      @Html.EnumDropDownListFor(expression, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(expression)
  </div>
}
@helper FormRow(表达式){
@(Html.LabelFor(表达式,new{@class=“control label col-sm-6 text right”}))
@EnumDropDownListFor(表达式,新{@class=“form control”})
@Html.ValidationMessageFor(表达式)
}
如果您的模型字段都是
string
,则可以将
MyClass
替换为
string


用定义的
TValue
定义两到三个helper可能并不坏,但如果您还有更多的helper会生成一些难看的代码,我并没有找到一个好的解决方案。我尝试从我放在
@functions{}
块中的一个函数包装
@helper
,但我从未让它沿着这条路径运行。

希望这是他们添加到Razor helpers未来版本中的东西。传统助手的可读性远远低于@helper语法。是的,我同意。恢复到旧的方法不仅很糟糕,而且会任意分割你的助手!您不必使该方法成为静态的,因此您也不需要传递您的Html/Url/MMM模型,为什么这对我不起作用?我得到了一个“无法在静态上下文中访问非静态方法‘thingtodo’。@Sheepy,这只对了一半。您是对的,您可以使它们成为非静态的,但是您只能获得
System.Web.WebPages.Html.HtmlHelper
,而不是
System.Web.Mvc.HtmlHelper
网页
版本很可能不适合您,因为大多数扩展方法都是针对
System.Web.Mvc.HtmlHelper
编写的。此外,没有
Url
属性,并且
UrlHelper
需要
RequestContext
,这在
网页
版本中不可用。总而言之,您可能必须通过
Mvc
HtmlHelper
。帮助程序必须是App_code文件夹的一部分??是的,此文件必须放在
{MyMvcProject}\App_code`中。当你把它放在别处时,它并不像广告上说的那样有效。当您将
MyHelper.cshtml`移动到
App\u code
中时,错误*无法访问静态上下文*中的非静态方法“thingtodo”
DoSomething
应该是静态的,这样您就可以在视图中调用
@MyHelper.DoSomething(…)
。如果将其设置为非静态,则需要首先创建
MyHelper
的实例。在当前的MVC 4版本中仍然没有修复:(这在VS2012中怎么还没有修复?天哪,我迫不及待地想添加它;我希望这是“昨天实现它”的地方。)在优先级列表上。部分脱离主题,但除此之外,我希望看到生成的类是
静态的
,除非实现细节禁止它;原因是,可以使用通用扩展助手:
@helper Foo(this to)where T:IBar{}
,这不是@Html.IdFor(…)是for?是的,您可以使用
@Htm.IdFor
,但需要额外的过程才能将其转换为字符串(
.ToHtmlString()
),当您考虑它时,助手需要string这一点很明显-如果它是
TModel
,您可能事先就知道了。
@using System.Web.Mvc;
@using System.Web.Mvc.Html;
@using System.Linq.Expressions;
@functions
{
    public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
    {
        return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr));
    }
}
@helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage)
{
    <p>
        @label
        <br />
        @textbox
        @validationMessage
    </p>
}
...
namespace System.Web.Mvc
{
    public static class MyHelpers
    {
        public static string GetNameForBinding<TModel, TProperty>
           (this HtmlHelper<TModel> model, 
            Expression<Func<TModel, TProperty>> property)
        {
            return ExpressionHelper.GetExpressionText(property);
        }
    }
}
@helper MyComponent(string name)
{
    <input name="@name" type="text"/>
}
@TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))
@helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) {
  <div class="form-group">
    @(Html.LabelFor(expression, new { @class = "control-label col-sm-6 text-right" }))
    <div class="col-sm-6">
      @Html.EnumDropDownListFor(expression, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(expression)
  </div>
}