我使用各种枚举作为下拉列表的来源。为了提供用户友好的描述,我为每个枚举添加了Description
属性,然后执行以下操作:
var list = Enum.GetValues(typeof(MyEnum))
.Cast<MyEnum>()
.ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description)
.ToList();
以上是重复的,因为我必须在很多地方使用它。我尝试添加扩展方法:
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();
}
然而,我得到一个例外:
无法将lambda表达式转换为类型'System.Collections.Generic.IEqualityComparer',因为它不是委托类型
将它用作扩展名的正确方法是什么(使用上述两种方法)?
答案 0 :(得分:6)
将它用作扩展名的正确方法是什么(使用上述两种方法)?
没有正确的方法将其用作扩展程序。当您具有值(实例)并且例如想要获取与该值相关的一些信息时,将使用扩展方法(类似于实例方法)。因此,如果您想获得单个enum
值的描述,扩展方法将有意义。
但是,在您的情况下,您需要的信息(enum
值/说明对列表)与特定enum
值无关,而与enum
无关输入即可。这意味着您只需要一个类似于Enum.TryParse<TEnum>
的简单静态泛型方法。理想情况下,您会将泛型参数限制为仅允许enum
,但是这种类型的约束(尚未支持),因此我们将where TEnum : struct
使用(类似于上述系统方法)并添加运行时检查。
所以这是一个示例实现:
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();
}
}
和用法:
public enum MyEnum
{
[Description("Foo")]
A,
[Description("Bar")]
B,
[Description("Baz")]
C,
}
var list = EnumInfo.GetList<MyEnum>();
答案 1 :(得分:2)
我的堆栈中有这个扩展方法,并且一直用它来做同样的事情。
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;
}
}
使用示例:
MyEnum.Value.Description(); // The value from within the description attr.
此外,您可以使用此ID来获取用于绑定目的的IDictionary。
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);
}
像这样使用它:
var dictionary = typeof(MyEnum).ToDictionary();
<强>更新强>
这是一个有效的.NET Fiddle。
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());
}
然后像这样使用它:
public enum Test
{
[Description("A test enum value for 'Foo'")]
Foo,
[Description("A test enum value for 'Bar'")]
Bar
}
typeof(Test).ToDictionary<Test>()
答案 2 :(得分:1)
您可以创建一个通用方法,将Enum
和Attribute
作为通用参数。
要获取任何属性,您可以创建一个扩展方法,如:
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);
}
以下是将其转换为字典的方法:
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));
}
您可以这样称呼它:
var test = eUserRole.SuperAdmin
.ToDictionary<eUserRole,EnumDisplayNameAttribute>(attr=>attr.DisplayName);
我以此枚举和属性为例:
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
}
答案 3 :(得分:0)
另一种观点:
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;
}
}
答案 4 :(得分:0)
每当我需要一个枚举(一个已知值的静态列表)需要不仅仅是一个整数值和一个字符串对应的东西时,我最终使用这个Enumeration Utility class本质上给我类似java的枚举行为。
因此,如果我选择这样的话,这将是我的第一选择,因为这样可以实现他/她想要的目标。
但是,假设这不是op的选项而且她/他需要坚持使用C#枚举,我会使用ehsan-sajjad和frank-j解决方案的组合:
以下是我将如何实现这一点:
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));
}
}
这就是用法的样子:
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);
}
}
答案 5 :(得分:0)
尝试替换
.ToDictionary(k => k, v => v.GetAttributeOfType<DescriptionAttribute>().Description)
与
.Select(t => new { k = t, v = t.GetAttributeOfType<DescriptionAttribute>().Description)
.ToDictionary(s => s.k, s => s.v)
在您的示例中,正在调用ToDictionary()的错误重载。