为什么说是写烂了的?这的确是写烂了的,N年就写过,网上一搜更是一大把
既然是写烂了的,为啥还要再写?首先因为网上都是仅仅反射获取,没考虑过额外的增加一个缓存步骤来提高性能;其次网上的也都只是对应特定特性,如果需要再支持其他特性就需要改下代码;最后如果是第三方枚举,本身并没提供任何描述特性,这里也可以通过一个额外的注册过程来达到与有描述特性一致的使用效果
因为仅是辅助类,所以无需长篇累牍,直接上代码
using System.Collections.Concurrent;
using System.Linq;
/// <summary>
/// 枚举辅助类
/// </summary>
public static class EnumExtensions
{
private static readonly ConcurrentDictionary<Type, Dictionary<long, string>> descDictionary
= new ConcurrentDictionary<Type, Dictionary<long, string>>();
/// <summary>
/// 获取枚举对应的描述,该方法仅简单的获取描述信息,如未注册过描述信息则直接返回ToString()结果
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string GetDescription(this Enum input)
{
var enumType = input.GetType();
if (enumType.IsEnum && descDictionary.TryGetValue(enumType, out Dictionary<long, string> dic) && dic != null)
{
var key = Convert.ToInt64(input);
if (dic.ContainsKey(key))
{
return dic[key];
}
}
return input?.ToString();
}
/// <summary>
/// 获取枚举对应的描述,该方法会在当前TEnum尚未注册描述信息时自动注册描述信息
/// </summary>
/// <typeparam name="TArrtibute">用于获取描述的Attribute</typeparam>
/// <param name="input">枚举值</param>
/// <param name="attrPropName">Attribute中用于获取描述值的public属性</param>
/// <returns></returns>
public static string GetDescription<TArrtibute>(this Enum input, string attrPropName = "Description")
where TArrtibute : Attribute
{
var enumType = input.GetType();
var attrType = typeof(TArrtibute);
RegisterDescription(enumType, attrType, out Dictionary<long, string> dic, attrPropName);
var key = Convert.ToInt64(input);
if (dic != null && dic.Count > 0 && dic.ContainsKey(key))
{
return dic[key];
}
return input?.ToString();
}
/// <summary>
/// 获取枚举所有的描述信息
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <returns></returns>
public static IDictionary<TEnum, string> GetDescriptions<TEnum>()
where TEnum : struct
{
var enumType = typeof(TEnum);
if (enumType.IsEnum && descDictionary.TryGetValue(enumType, out Dictionary<long, string> dic) && dic != null)
{
return dic.ToDictionary(k => Enum.Parse<TEnum>(k.Key.ToString()), v => v.Value);
}
return null;
}
/// <summary>
/// 注册枚举的描述,假如已注册过属性描述信息,则该方法将不进行任何处理
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <typeparam name="TArrtibute">用于获取描述的Attribute</typeparam>
/// <param name="attrPropName">Attribute中用于获取描述值的public属性</param>
public static void RegisterDescription<TEnum, TArrtibute>(string attrPropName = "Description")
where TEnum : struct
where TArrtibute : Attribute
{
var enumType = typeof(TEnum);
var attrType = typeof(TArrtibute);
RegisterDescription(enumType, attrType, out Dictionary<long, string> dictionary, attrPropName);
}
/// <summary>
/// 注册枚举的描述,默认按<see cref="System.ComponentModel.DescriptionAttribute"/>进行注册
/// </summary>
/// <typeparam name="TEnum"></typeparam>
public static void RegisterDescription<TEnum>()
where TEnum : struct
{
RegisterDescription<TEnum, System.ComponentModel.DescriptionAttribute>();
}
/// <summary>
/// 注册枚举的描述,注意此处的注册会替换已有的描述枚举(假如有)
/// </summary>
/// <typeparam name="TEnum"></typeparam>
/// <param name="dictionary">包含描述的字典</param>
public static void RegisterDescription<TEnum>(IDictionary<TEnum, string> dictionary)
where TEnum : struct
{
var enumType = typeof(TEnum);
if (enumType.IsEnum)
{
var dic = dictionary.ToDictionary(k => Convert.ToInt64(k.Key), v => v.Value);
descDictionary.AddOrUpdate(enumType, dic, (k, v) => dic);
}
}
private static void RegisterDescription(Type enumType, Type attrType, out Dictionary<long, string> dictionary, string attrPropName)
{
dictionary = null;
//仅枚举时才进行注册
if (enumType.IsEnum
&& !descDictionary.TryGetValue(enumType, out dictionary))
{
var arrs = Enum.GetValues(enumType);
dictionary = new Dictionary<long, string>();
foreach (var e in arrs)
{
var desc = e.ToString();
var attrs = enumType.GetField(desc).GetCustomAttributes(attrType, false);
if (attrs.Length > 0)
{
var prop = attrs[0].GetType().GetProperty(attrPropName);
if (prop != null)
{
desc = prop.GetValue(attrs[0]).ToString();
}
}
dictionary.Add(Convert.ToInt64(e), desc);
}
descDictionary.TryAdd(enumType, dictionary);
}
}
}
使用例子如下,首先是两个自定义枚举
enum SecondDemoEnum
{
[DebuggerDisplay("DebuggerDisplay.X")]
X = 9,
[DebuggerDisplay("DebuggerDisplay.Y")]
Y = 12,
Z = 18
}
enum FirstDemoEnum : byte
{
[Description("Description[A]")]
A,
[Description("Description[B]")]
B,
C
}
然后是具体的例子代码
Console.WriteLine("枚举 {0} 对应描述 {1}",DateTimeKind.Local, DateTimeKind.Local.GetDescription());
//对于没有设置Attribute的枚举,可以通过以下方式注册描述值
var dic = new Dictionary<DateTimeKind, string> { { DateTimeKind.Local, "本地时间" } };
//注意此处注册字典时不能直接注册为 Dictionary<Enum, string>
EnumHelper.RegisterDescription(dic);
Console.WriteLine("枚举 {0} 对应描述 {1}", DateTimeKind.Local, DateTimeKind.Local.GetDescription());
//描述属性为DescriptionAttribute的demo
foreach (var demoEnum in Enum.GetValues(typeof(FirstDemoEnum)))
{
FirstDemoEnum input = (FirstDemoEnum)demoEnum;
Console.WriteLine("枚举 {0} 对应描述 {1}", input, input.GetDescription<DescriptionAttribute>());
}
//描述属性为DebuggerDisplayAttribute的demo
foreach (var demoEnum in Enum.GetValues(typeof(SecondDemoEnum)))
{
SecondDemoEnum input = (SecondDemoEnum)demoEnum;
//因为DebuggerDisplayAttribute默认属性对应Value,所以此处需传入属性名
Console.WriteLine("枚举 {0} 对应描述 {1}", input, input.GetDescription<DebuggerDisplayAttribute>("Value"));
}
执行结果如下