C# 使用泛型和LINQ的MVC3 HTMLHelper

C# 使用泛型和LINQ的MVC3 HTMLHelper,c#,linq,asp.net-mvc-3,html-helper,C#,Linq,Asp.net Mvc 3,Html Helper,已更新 我正在尝试创建一个HtmlHelper扩展,它能够获取一组tModel。然后设置一个表达式,该表达式将获取集合中每个项的声明属性并将它们打印出来 下面的代码确实有效。然而,我不喜欢我目前拥有的模式中的一件事是泛型类型没有被推断出来。我必须声明扩展方法的类型 我试图遵循Telerik用于其网格的模式类型,当您声明一个模型时,将推断出泛型类型 在我看来,我想这样做: @model List<MyProject.MyModels.UserModel> @(Html.MyExtens

已更新

我正在尝试创建一个HtmlHelper扩展,它能够获取一组tModel。然后设置一个表达式,该表达式将获取集合中每个项的声明属性并将它们打印出来

下面的代码确实有效。然而,我不喜欢我目前拥有的模式中的一件事是泛型类型没有被推断出来。我必须声明扩展方法的类型

我试图遵循Telerik用于其网格的模式类型,当您声明一个模型时,将推断出泛型类型

在我看来,我想这样做:

@model List<MyProject.MyModels.UserModel>
@(Html.MyExtensions()
      .PrintUsers(Model)
      .FirstName(m => m.FirstName)
      .LastName(m => m.LastName)
)
所以我有一个
HtmlHelper
,看起来像这样:

public static class UIExtension
{
    public static ComponentFactory<TModel, T> MyExtensions<TModel, T>(this HtmlHelper<TModel> html) 
        where TModel : IEnumerable<T>
        where T : class
    {
        return new ComponentFactory<TModel, T>(html);
    }
}
public static class UIExtension
{
    public static ComponentFactory<TModel> MyExtensions<TModel>(this HtmlHelper<IEnumerable<TModel>> html) where TModel : class

    {
        return new ComponentFactory<TModel>(html);
    }
}
public class UserModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class ComponentFactory<TModel>
where TModel : class
{
    private HtmlHelper _html;

    public ComponentFactory()
    {
    }

    public ComponentFactory(HtmlHelper<IEnumerable<TModel>> html)
    {
        this._html = html;
    }

    public ListComponent<TModel> PrintUsers(IEnumerable<TModel> model)
    {
        return new ListComponent<TModel>(model);
    }

    /* Add other ui components to this factory */
}
public class ListComponent<T> : IHtmlString
{
    private Expression<Func<T, string>> _firstname;
    private Expression<Func<T, string>> _lastname;

    private IEnumerable<T> _model;

    public ListComponent(IEnumerable<T> model)
    {
        this._model = model;
    }

    public ListComponent<T> FirstName(Expression<Func<T, string>> property)
    {
        this._firstname = property;
        return this;
    }

    public ListComponent<T> LastName(Expression<Func<T, string>> property)
    {
        this._lastname = property;
        return this;
    }



public override MvcHtmlString Render()
{
    TagBuilder container = new TagBuilder("div");

    TagBuilder title = new TagBuilder("div");
    title.InnerHtml = "<b>Names</b>";
    container.InnerHtml = title.ToString(TagRenderMode.Normal);

    TagBuilder ul = new TagBuilder("ul");

    foreach (var item in this._model)
    {
        TagBuilder li = new TagBuilder("li");
        li.SetInnerText(String.Format("{0} {1}", _firstname.Compile()(item), _lastname.Compile()(item)));
        ul.InnerHtml += li.ToString(TagRenderMode.Normal);
    }

    container.InnerHtml += ul.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(container.ToString(TagRenderMode.Normal));
}
}
然后我的
列表组件

public class ListComponent<T> : IHtmlString
{
    private Expression<Func<T, string>> _firstname;
    private Expression<Func<T, string>> _lastname;

    private IEnumerable<T> _model;

    public ListComponent(IEnumerable<T> model)
    {
        this._model = model;
    }

    public ListComponent<T> FirstName(Expression<Func<T, string>> property)
    {
        this._firstname = property;
        return this;
    }

    public ListComponent<T> LastName(Expression<Func<T, string>> property)
    {
        this._lastname = property;
        return this;
    }

    public override MvcHtmlString Render()
    {
        TagBuilder container = new TagBuilder("div");

        TagBuilder title = new TagBuilder("div");
        title.InnerHtml = "<b>Names</b>";
        container.InnerHtml = title.ToString(TagRenderMode.Normal);

        TagBuilder ul = new TagBuilder("ul");

        foreach (var item in this._model)
        {
            TagBuilder li = new TagBuilder("li");
            li.SetInnerText(String.Format("{0} {1}", _firstname.Compile()(item), _lastname.Compile()(item)));
            ul.InnerHtml += li.ToString(TagRenderMode.Normal);
        }

        container.InnerHtml += ul.ToString(TagRenderMode.Normal);

        return MvcHtmlString.Create(container.ToString(TagRenderMode.Normal));
    }
}
公共类列表组件:IHtmlString
{
私有表达式_firstname;
私有表达式_lastname;
私有IEnumerable_模型;
公共列表组件(IEnumerable模型)
{
这个._model=model;
}
公共ListComponent名字(表达式属性)
{
这个。_firstname=属性;
归还这个;
}
公共ListComponent LastName(表达式属性)
{
这是。_lastname=property;
归还这个;
}
公共覆盖MvcHtmlString Render()
{
标记生成器容器=新标记生成器(“div”);
标记生成器标题=新标记生成器(“div”);
title.InnerHtml=“名称”;
container.InnerHtml=title.ToString(TagRenderMode.Normal);
标记生成器ul=新标记生成器(“ul”);
foreach(此.\u模型中的var项目)
{
标记生成器li=新标记生成器(“li”);
SetInnerText(String.Format(“{0}{1}”,_firstname.Compile()(item),_lastname.Compile()(item));
ul.InnerHtml+=li.ToString(TagRenderMode.Normal);
}
container.InnerHtml+=ul.ToString(TagRenderMode.Normal);
返回MvcHtmlString.Create(container.ToString(TagRenderMode.Normal));
}
}

谢谢你的帮助和建议

您可以使用两个类型参数,一个用于列表,一个用于项目类型:

ListComponent<TList, TItem> Print<TList, TItem>(TList list) where TList : IEnumerable<TItem>
ListComponent打印(TList列表),其中TList:IEnumerable
更新: 也许这样类型推断会起作用:

ListComponent<TItem> Print<TItem>(IEnumerable<TItem> list)
ListComponent打印(IEnumerable列表)

像这样的东西怎么样:

public static class UIExtension
{
    public static ComponentFactory<TModel, T> MyExtensions<TModel, T>(this HtmlHelper<TModel> html) 
        where TModel : IEnumerable<T>
        where T : class
    {
        return new ComponentFactory<TModel, T>(html);
    }
}
public static class UIExtension
{
    public static ComponentFactory<TModel> MyExtensions<TModel>(this HtmlHelper<IEnumerable<TModel>> html) where TModel : class

    {
        return new ComponentFactory<TModel>(html);
    }
}
public class UserModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class ComponentFactory<TModel>
where TModel : class
{
    private HtmlHelper _html;

    public ComponentFactory()
    {
    }

    public ComponentFactory(HtmlHelper<IEnumerable<TModel>> html)
    {
        this._html = html;
    }

    public ListComponent<TModel> PrintUsers(IEnumerable<TModel> model)
    {
        return new ListComponent<TModel>(model);
    }

    /* Add other ui components to this factory */
}
public class ListComponent<T> : IHtmlString
{
    private Expression<Func<T, string>> _firstname;
    private Expression<Func<T, string>> _lastname;

    private IEnumerable<T> _model;

    public ListComponent(IEnumerable<T> model)
    {
        this._model = model;
    }

    public ListComponent<T> FirstName(Expression<Func<T, string>> property)
    {
        this._firstname = property;
        return this;
    }

    public ListComponent<T> LastName(Expression<Func<T, string>> property)
    {
        this._lastname = property;
        return this;
    }



public override MvcHtmlString Render()
{
    TagBuilder container = new TagBuilder("div");

    TagBuilder title = new TagBuilder("div");
    title.InnerHtml = "<b>Names</b>";
    container.InnerHtml = title.ToString(TagRenderMode.Normal);

    TagBuilder ul = new TagBuilder("ul");

    foreach (var item in this._model)
    {
        TagBuilder li = new TagBuilder("li");
        li.SetInnerText(String.Format("{0} {1}", _firstname.Compile()(item), _lastname.Compile()(item)));
        ul.InnerHtml += li.ToString(TagRenderMode.Normal);
    }

    container.InnerHtml += ul.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(container.ToString(TagRenderMode.Normal));
}
}

在看了@Tomas的答案后,它帮助我意识到我在模式中遗漏了什么。尽管@Tomas的回答确实让我在
视图
中得到了我想要的语法,其中
模型
被正确推断,但唯一的退步是整个
视图模型
IEnumerable
绑定。由于我想绑定到我的
ViewModel
中属于IEnumerable的一个属性,我做了一些更改,结果成功了

HtmlHelper
扩展名:

public static class UIExtension
{
   public static ComponentFactory MyExtensions(this HtmlHelper html)
   {
       return new ComponentFactory(html);
   }

   public static ComponentFactory<TModel> MyExtensions<TModel>(this HtmlHelper<TModel> html) 
      where TModel : class
   {
       return new ComponentFactory<TModel>(html);
   }
}
因此,主要的变化是,对于
PrintUsers
方法,我使用不同的泛型类型来处理该部分。这样,我的
模型
就可以由开发人员决定,他们只需将
属性
设置为
列表组件的
数据源

所以现在在
视图中
非常灵活,我可以这样做

@(Html.MyExtensions()
      .PrintUsers(Model.MyList)
      .FirstName(m => m.FirstName)
      .LastName(m => m.LastName)
)

我确实尝试了两个类型参数,我唯一不喜欢的是,按照我现在的组织方式,它们的类型是不可推断的。我想用类似Teleriar Telerik的图案。当你声明模型时,它会推断出类型。这与我想要的非常接近。它确实帮助我找到了我的整体解决方案,我将发布+1@Gabe很好,期待看到您的解决方案。很好,它给了你一些灵感。:-)
public static class UIExtension
{
   public static ComponentFactory MyExtensions(this HtmlHelper html)
   {
       return new ComponentFactory(html);
   }

   public static ComponentFactory<TModel> MyExtensions<TModel>(this HtmlHelper<TModel> html) 
      where TModel : class
   {
       return new ComponentFactory<TModel>(html);
   }
}
public class ComponentFactory<TModel>
{
   private HtmlHelper<TModel> _html;
   public ComponentFactory(HtmlHelper<TModel> html)
   {
      this._html = html;
   }

   public ListComponent<TObj> PrintUsers<TObj>(IEnumerable<TObj> model)
   {
      return new ListComponent<TObj>(model);
   }
}
@(Html.MyExtensions()
      .PrintUsers(Model.MyList)
      .FirstName(m => m.FirstName)
      .LastName(m => m.LastName)
)