Enum to list as an extension?
我有各种枚举用作下拉列表的源,为了提供用户友好的描述,我向每个枚举添加了
1 2 3 4 | var list = Enum.GetValues(typeof(MyEnum)) .Cast<MyEnum>() .ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description) .ToList(); |
上面是重复的,因为我必须在很多地方使用它。我尝试添加扩展方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static T GetAttributeOfType<T>(this Enum enumVal) where T : System.Attribute { var type = enumVal.GetType(); var memInfo = type.GetMember(enumVal.ToString()); var attributes = memInfo[0].GetCustomAttributes(typeof(T), false); return (attributes.Length > 0) ? (T)attributes[0] : null; } public static KeyValuePair<T, string> ToList<T>(this Enum source) { return Enum.GetValues(typeof(T)) .Cast<T>() .ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description) .ToList(); } |
但是,我得到一个例外:
Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer' because it is not a delegate type
使用它作为扩展的正确方法是什么(使用上述2种方法)?
What is the correct way to use it as an extension (using the above 2 methods)?
没有正确的方法将其用作扩展名。当您有一个值(实例)并且希望获得与该值相关的一些信息时,将使用扩展方法(类似于实例方法)。因此,如果您想获得单个
但是,在您的情况下,您需要的信息(
下面是一个示例实现:
1 2 3 4 5 6 7 8 9 10 11 | public static class EnumInfo { public static List<KeyValuePair<TEnum, string>> GetList<TEnum>() where TEnum : struct { if (!typeof(TEnum).IsEnum) throw new InvalidOperationException(); return ((TEnum[])Enum.GetValues(typeof(TEnum))) .ToDictionary(k => k, v => ((Enum)(object)v).GetAttributeOfType<DescriptionAttribute>().Description) .ToList(); } } |
用途:
1 2 3 4 5 6 7 8 9 10 11 | public enum MyEnum { [Description("Foo")] A, [Description("Bar")] B, [Description("Baz")] C, } var list = EnumInfo.GetList<MyEnum>(); |
我的堆栈中有这个扩展方法,并且一直在为相同的事情使用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static string Description(this Enum @enum) { try { var @string = @enum.ToString(); var attribute = @enum.GetType() .GetField(@string) .GetCustomAttribute<DescriptionAttribute>(false); return attribute != null ? attribute.Description : @string; } catch // Log nothing, just return an empty string { return string.Empty; } } |
示例用法:
1 | MyEnum.Value.Description(); // The value from within the description attr. |
此外,您可以使用此方法获取用于绑定目的的IDictionary。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static IDictionary<string, string> ToDictionary(this Type type) { if (!type.IsEnum) { throw new InvalidCastException("'enumValue' is not an Enumeration!"); } var names = Enum.GetNames(type); var values = Enum.GetValues(type); return Enumerable.Range(0, names.Length) .Select(index => new { Key = names[index], Value = ((Enum)values.GetValue(index)).Description() }) .ToDictionary(k => k.Key, k => k.Value); } |
像这样使用它:
1 |
更新
这是一个正在工作的.NET小提琴。
1 2 3 4 5 6 7 | public static Dictionary<TEnum, string> ToDictionary<TEnum>(this Type type) where TEnum : struct, IComparable, IFormattable, IConvertible { return Enum.GetValues(type) .OfType<TEnum>() .ToDictionary(value => value, value => value.Description()); } |
然后这样使用:
1 2 3 4 5 6 7 8 9 | public enum Test { [Description("A test enum value for 'Foo'")] Foo, [Description("A test enum value for 'Bar'")] Bar } typeof(Test).ToDictionary<Test>() |
您可以创建一个将
要获取任何属性,可以创建如下扩展方法:
1 2 3 4 5 6 7 8 9 | public static string AttributeValue<TEnum,TAttribute>(this TEnum value,Func<TAttribute,string> func) where T : Attribute { FieldInfo field = value.GetType().GetField(value.ToString()); T attribute = Attribute.GetCustomAttribute(field, typeof(T)) as T; return attribute == null ? value.ToString() : func(attribute); } |
下面是将其转换为字典的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static Dictionary<TEnum,string> ToDictionary<TEnum,TAttribute>(this TEnum obj,Func<TAttribute,string> func) where TEnum : struct, IComparable, IFormattable, IConvertible where TAttribute : Attribute { return (Enum.GetValues(typeof(TEnum)).OfType<TEnum>() .Select(x => new { Value = x, Description = x.AttributeValue<TEnum,TAttribute>(func) }).ToDictionary(x=>x.Value,x=>x.Description)); } |
你可以这样称呼它:
1 2 | var test = eUserRole.SuperAdmin .ToDictionary<eUserRole,EnumDisplayNameAttribute>(attr=>attr.DisplayName); |
我使用这个枚举和属性作为示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class EnumDisplayNameAttribute : Attribute { private string _displayName; public string DisplayName { get { return _displayName; } set { _displayName = value; } } } public enum eUserRole : int { [EnumDisplayName(DisplayName ="Super Admin")] SuperAdmin = 0, [EnumDisplayName(DisplayName ="Phoenix Admin")] PhoenixAdmin = 1, [EnumDisplayName(DisplayName ="Office Admin")] OfficeAdmin = 2, [EnumDisplayName(DisplayName ="Report User")] ReportUser = 3, [EnumDisplayName(DisplayName ="Billing User")] BillingUser = 4 } |
输出:
尝试替换
1 | .ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description) |
具有
16在您的示例中,正在调用错误的toDictionary()重载。
每当我需要一个枚举(一个已知值的静态列表)时,它需要的不仅仅是一个整数值和一个字符串对应项,最后我会使用这个枚举实用工具类,它基本上给了我类似Java的枚举行为。
所以这是我的第一个选择,如果我是欧普的鞋子,因为这将使它真正的琐碎实现他/她想要的。
但是,假设这不是OP的选择,她/他需要坚持使用C Enums,我将同时使用ehsan sajjad和frank-j解决方案:
以下是我将如何实现这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public static class EnumUtils { public static string GetDescription(this Enum enumVal) { var type = enumVal.GetType(); var memInfo = type.GetMember(enumVal.ToString()); var attributes = memInfo[0].GetCustomAttributes(typeof (DescriptionAttribute), false); return (attributes.Length > 0) ? ((DescriptionAttribute) attributes[0]).Description : null; } public static Dictionary<TEnum, string> GetItemsWithDescrition<TEnum>() { var enumType = typeof(TEnum); if (!enumType.IsEnum) { throw new InvalidOperationException("TEnum must be an enum type"); } return Enum .GetValues(enumType) .Cast<TEnum>() .ToDictionary(enumValue => enumValue, enumValue => GetDescription(enumValue as Enum)); } } |
下面是用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public class EnumUtilsTests { public enum MyEnum { [Description("Um")] One, [Description("Dois")] Two, [Description("Tres")] Three, NoDescription } public void Should_get_enum_description() { MyEnum.One.GetDescription().ShouldBe("Um"); MyEnum.Two.GetDescription().ShouldBe("Dois"); MyEnum.Three.GetDescription().ShouldBe("Tres"); MyEnum.NoDescription.GetDescription().ShouldBe(null); } public void Should_get_all_enum_values_with_description() { var response = EnumUtils.GetItemsWithDescrition<MyEnum>(); response.ShouldContain(x => x.Key == MyEnum.One && x.Value =="Um"); response.ShouldContain(x => x.Key == MyEnum.Two && x.Value =="Dois"); response.ShouldContain(x => x.Key == MyEnum.Three && x.Value =="Tres"); response.ShouldContain(x => x.Key == MyEnum.NoDescription && x.Value == null); } } |
另一个观点是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | class Program { //Example enum public enum eFancyEnum { [Description("Obsolete")] Yahoo, [Description("I want food")] Meow, [Description("I want attention")] Woof, } static void Main(string[] args) { //This is how you use it Dictionary<eFancyEnum, string> myDictionary = typeof(eFancyEnum).ToDictionary<eFancyEnum>(); } } public static class EnumExtension { //Helper method to get description public static string ToDescription<T>(this T 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(); } //The actual extension method that builds your dictionary public static Dictionary<T, string> ToDictionary<T>(this Type source) where T : struct, IConvertible { if(!source.IsEnum || typeof(T) != source) { throw new InvalidEnumArgumentException("BOOM"); } Dictionary<T, string> retVal = new Dictionary<T,string>(); foreach (var item in Enum.GetValues(typeof(T)).Cast<T>()) { retVal.Add(item, item.ToDescription()); } return retVal; } } |