【问题标题】:Generic Enum to SelectList extension method通用枚举到 SelectList 扩展方法
【发布时间】:2013-08-11 07:05:29
【问题描述】:

我需要从我的项目中的任何Enum 创建一个SelectList

我有下面的代码,我从特定枚举创建一个选择列表,但我想为任何枚举创建一个扩展方法。此示例检索每个 Enum 值上的 DescriptionAttribute 的值

var list = new SelectList(
            Enum.GetValues(typeof(eChargeType))
            .Cast<eChargeType>()
            .Select(n => new
                {
                    id = (int)n, 
                    label = n.ToString()
                }), "id", "label", charge.type_id);

引用this post,我该怎么做?

public static void ToSelectList(this Enum e)
{
    // code here
}

【问题讨论】:

    标签: c# asp.net-mvc enums extension-methods selectlist


    【解决方案1】:

    这是 Nathaniels 答案的更正 [type casted value to int] 和简化 [uses tostring override 而不是 getname] 版本,它返回 List 而不是数组:

    public static class Enum<T>
    {
        //usage: var lst =  Enum<myenum>.GetSelectList();
        public static List<SelectListItem> GetSelectList()
        {
            return  Enum.GetValues( typeof(T) )
                    .Cast<object>()
                    .Select(i => new SelectListItem()
                                 { Value = ((int)i).ToString()
                                  ,Text = i.ToString() })
                    .ToList();
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      由于 enum 不能将扩展固定到整个集合,因此扩展 Enum 基类的便捷方法是使用静态类型类。这将允许简洁的代码,例如:

      Enum<MyCustomEnumType>.GetSelectItems();
      

      可以通过以下代码实现:

      public static class Enum<T>
      {
          public static SelectListItem[] GetSelectItems()
          {
              Type type = typeof(T);
              return
                  Enum.GetValues(type)
                      .Cast<object>()
                      .Select(v => new SelectListItem() { Value = v.ToString(), Text = Enum.GetName(type, v) })
                      .ToArray();
          }
      }
      

      由于枚举没有共享接口类型误用是可能的,但类名 Enum 应该消除任何混淆。

      【讨论】:

        【解决方案3】:

        聚会迟到了,但由于没有公认的答案,它可能会帮助其他人:

        正如@Maarten 提到的,扩展方法适用于枚举的值,而不是枚举类型 itelf,因此使用 Maarteen 的灵魂,您可以创建一个虚拟或默认值来调用扩展方法,但是,您可能会发现,正如我所做的那样,只使用这样的静态辅助方法会更简单:

        public static class EnumHelper
        {
            public static SelectList GetSelectList<T>(string selectedValue, bool useNumeric = false)
            {
                Type enumType = GetBaseType(typeof(T));
        
                if (enumType.IsEnum)
                {
                    var list = new List<SelectListItem>();
        
                    // Add empty option
                    list.Add(new SelectListItem { Value = string.Empty, Text = string.Empty });
        
                    foreach (Enum e in Enum.GetValues(enumType))
                    {
                        list.Add(new SelectListItem { Value = useNumeric ? Convert.ToInt32(e).ToString() : e.ToString(), Text = e.Description() });
                    }
        
                    return new SelectList(list, "Value", "Text", selectedValue);
                }
        
                return null;
            }
        
            private static bool IsTypeNullable(Type type)
            {
                return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
            }
        
            private static Type GetBaseType(Type type)
            {
                return IsTypeNullable(type) ? type.GetGenericArguments()[0] : type;
            } 
        

        您可以像这样创建选择列表:

         viewModel.ProvinceSelect =  EnumHelper.GetSelectList<Province>(model.Province);
        

        或使用可选的数值代替字符串:

        viewModel.MonthSelect =  EnumHelper.GetSelectList<Month>(model.Month,true);
        

        我从here 那里得到了基本的想法,虽然我改变了它以适应我的需要。我添加的一件事是可以选择使用整数作为值。我还添加了一个枚举扩展来获取基于 this 博客文章的描述属性:

        public static class EnumExtensions
        {
            public static string Description(this Enum en)
            {
                Type type = en.GetType();
        
                MemberInfo[] memInfo = type.GetMember(en.ToString());
        
                if (memInfo != null && memInfo.Length > 0)
                {
                    object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        
                    if (attrs != null && attrs.Length > 0)
                    {
                        return ((DescriptionAttribute)attrs[0]).Description;
                    }
                }
        
                return en.ToString();
            }       
        } 
        

        【讨论】:

          【解决方案4】:

          我认为您正在苦苦挣扎的是描述的检索。我敢肯定,一旦你有了这些,你就可以定义你的最终方法来给出你的确切结果。

          首先,如果你定义一个扩展方法,它作用于枚举的值,而不是枚举类型本身。而且我认为,为了便于使用,您希望在类型上调用该方法(如静态方法)。不幸的是,您无法定义这些。

          您可以执行以下操作。首先定义一个检索枚举值描述的方法,如果有的话:

          public static string GetDescription(this Enum value) {
              string description = value.ToString();
              FieldInfo fieldInfo = value.GetType().GetField(description);
              DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
          
              if (attributes != null && attributes.Length > 0) {
                  description = attributes[0].Description;
              }
              return description;
          }
          

          接下来,定义一个获取枚举所有值的方法,并使用前面的方法查找我们想要显示的值,并返回该列表。可以推断出泛型参数。

          public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>(this TEnum value) {
              return Enum
                  .GetValues(typeof(TEnum))
                  .Cast<TEnum>()
                  .Select(x => new KeyValuePair<TEnum, string>(x, ((Enum)((object)x)).GetDescription()))
                  .ToList();
          }
          

          最后,为了方便使用,一个方法可以直接调用它而没有值。但是通用参数不是可选的。

          public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>() {
              return ToEnumDescriptionsList<TEnum>(default(TEnum));
          }
          

          现在我们可以这样使用它:

          enum TestEnum {
              [Description("My first value")]
              Value1,
              Value2,
              [Description("Last one")]
              Value99
          }
          
          var items = default(TestEnum).ToEnumDescriptionsList();
          // or: TestEnum.Value1.ToEnumDescriptionsList();
          // Alternative: EnumExtensions.ToEnumDescriptionsList<TestEnum>()
          foreach (var item in items) {
              Console.WriteLine("{0} - {1}", item.Key, item.Value);
          }
          Console.ReadLine();
          

          哪些输出:

          Value1 - My first value
          Value2 - Value2
          Value99 - Last one
          

          【讨论】:

          • 感谢您的详细回复 :) 老实说,我只是想要一些非常简单的东西(如果可能的话),所以我可以使用 eChargeType.ToSelectList() - 我已经降低了示例的复杂性以排除 @987654328 @ 因为这可能会增加不必要的混乱。谢谢!
          • 不幸的是,eChargeType.ToSelectList() 是不可能的,因为您想将静态方法添加到枚举类型。这是不可能的,但你可以在某处创建一个静态辅助方法。
          • 参考您上面的评论,您能否阐明这篇文章的作者希望实现的目标? stackoverflow.com/a/276589/175893我还以为我们是同一个任务呢!谢谢
          猜你喜欢
          • 2010-09-21
          • 1970-01-01
          • 2015-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多