【问题标题】:Generic Function using TModel to Convert to IEnumerable<SelectListItem>使用 TModel 转换为 IEnumerable<SelectListItem> 的通用函数
【发布时间】:2017-02-01 21:25:22
【问题描述】:

我发现this 文章展示了如何将 List 转换为 IEnumerable。有人可以向我解释一下是否可以将其转换为可供许多列表使用的通用函数?

例如,我有一个

public class City
{
    public int CityId { get; set; }
    public string CityName { get; set; }
}
public class State 
{
    public int StateId { get; set; }
    public string StateName { get; set; }
    public string StateAbbreviation { get; set; }
}

然后我有这两个列表,我想在其中显示一个下拉列表:

List<City> cities
List<State> states

我可以设置 2 种不同的方法来做类似的事情,但是我必须将此代码复制/粘贴到多个列表中,这不是我想要的。

public static IEnumerable<SelectListItem> GetCitiesSelectList()
{
    IEnumerable<SelectListItem> cityList = GetCities().Select(x => new SelectListItem() { Text = x.CityName, Value = x.CityId.ToString() });
    return qList;
}

我想知道是否有类似的东西,但能够传入任何类型的列表并传入列表的文本和值?我知道你可以用TModel 做点什么,但我并不完全理解它,希望有人能把我推向正确的方向。

【问题讨论】:

  • 为什么是 StateName , CityName ?为什么不只是名字

标签: c# asp.net-mvc asp.net-mvc-5


【解决方案1】:

这个呢:

var cities = new SelectList(cityList, "CityId", "CityName");
var states = new SelectList(cityList, "StateId", "StateAbbreviation");

SelectList 可转换为 IEnumerable&lt;SelectListItem&gt;

【讨论】:

    【解决方案2】:

    您编写的任何通用方法都不会比仅使用 Linq Select 简单得多:

    var cityList = cities.Select(c => new SelectListItem
    {
        Name = c.CityName,
        Value = c.CityId.ToString()
    });
    

    但如果你真的想让它通用,你可以这样做:

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> input,
        Func<T, string> valueFunc,
        Func<T, string> nameFunc)
    {
        return input.Select(i => new SelectListItem
        {
            Value = valueFunc(i),
            Name = nameFunc(i)
        });
    }
    

    并像这样使用:

    var cityList = cities.ToSelectList(c => c.CityId.ToString(), c => c.CityName);
    

    【讨论】:

      【解决方案3】:

      @miguelerm 的回答很可靠。但是,如果您不习惯将字符串常量用于属性,您可以为此转换创建一个扩展方法:

      public static class EnumerableExtensions
      {
          public static IEnumerable<SelectListItem> ToSelectList<T>(
             this IEnumerable<T> collection,
             Func<T, object> textSelector,
             Func<T, object> valueSelector)
          {
              // null checking omitted for brevity
              foreach (var item in collection)
              {
                  yield return new SelectListItem()
                  {
                      Text = textSelector(item) as string,
                      Value = valueSelector(item) as string
                  };
              }
          }
      }
      

      你可以像这样在 Razor 中使用它:

      @Html.DropDownListFor(m => m.SelectedCity, Model.Cities.ToSelectList(c => c.CityName, city => c.CityId))
      

      【讨论】:

      • 虽然我同意@miguelerm 的答案是可靠的,但我的想法与您在此处描述的完全一样。
      • @Dan 我选择了object 以避免在调用之前将值显式转换为字符串。如果您可以在 Razor 中更加明确,您绝对可以将签名切换为使用 string 值。我认为不需要使用 LINQ 进行投影,并且它的代码非常简单。
      • 我同意你的观点@will-ray,另一个选择是使用 nameof(如果你使用的是 C# 6.0)。 new SelectList(cities, nameof(City.CityId), nameof(City.CityName));
      【解决方案4】:

      创建一个基类SelectListItem

      public class SelectListItem
      {
          public virtual string Text { get; set; }
          public virtual string Value { get; set; }
      }
      
      public class City : SelectListItem
      {
          public int CityId { get; set; }
          public string CityName { get; set; }
          public override string Text
          {
              get { return CityName; }
              set { CityName = value; }
          }
          public override string Value
          {
              get { return CityId.ToString(); }
              set { CityId = (int)value; }
          }
      }
      public class State : SelectListItem
      {
          public int StateId { get; set; }
          public string StateName { get; set; }
          public string StateAbbreviation { get; set; }
          public override string Text
          {
              get { return StateName; }
              set { StateName = value; }
          }
          public override string Value
          {
              get { return StateId.ToString(); }
              set { StateId = (int)value; }
          }
      }
      

      【讨论】:

        【解决方案5】:

        一致地命名您的模型将是最简单的方法。假设您有单独的下拉实体,例如{ Id , Name},并使用该通用模型进行下拉转换。 公共类下拉 {

            public IEnumerable<int> SelectedItems
            {
                get;
                set;
            }
        
        
            public IEnumerable<SelectListItem> Items
            {
                get;
                set;
            }
        
        
            public IEnumerable<string> SelectedItemsString
            {
                get;
                set;
            }
        }
        

        无论您要转换多少个列表项,都将列表传递给辅助方法,该方法使用下拉实体进行转换并返回您所期望的!!

        IEnumerable<SelectListItem> dropdownItems = new MultiSelectList(YourEntity, "ID", "Name", selectedId);
                    DropDown fboDropDown = new DropDown { Items = dropdownItems, SelectedItems = selectedId };
        

        可用于下拉和多选列表

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多