来源: C#自定义Attribute值的获取与优化 – junjieok – 博客园
C#自定义Attribute值的获取是开发中会经常用到的,一般我们的做法也就是用反射进行获取的,代码也不是很复杂。
1、首先有如下自定义的Attribute
1 [AttributeUsage(AttributeTargets.All)] 2 public sealed class NameAttribute : Attribute 3 { 4 private readonly string _name; 5 6 public string Name 7 { 8 get { return _name; } 9 } 10 11 public NameAttribute(string name) 12 { 13 _name = name; 14 } 15 }
2、定义一个使用NameAttribute的类
1 [Name("dept")] 2 public class CustomAttributes 3 { 4 [Name("Deptment Name")] 5 public string Name { get; set; } 6 7 [Name("Deptment Address")] 8 public string Address; 9 }
3、获取CustomAttributes类上的”dept”也就很简单了
1 private static string GetName() 2 { 3 var type = typeof(CustomAttributes); 4 5 var attribute = type.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); 6 7 if (attribute == null) 8 { 9 return null; 10 } 11 12 return ((NameAttribute)attribute).Name; 13 }
以上代码就可以简单的获取,类上的Attribute的值了,但是需求往往不是这么简单的,不仅要获取类头部Attribute上的值,还要获取字段Address头部Attribute上的值。有的同学可能就觉得这还不简单呀,直接上代码
1 private static string GetAddress() 2 { 3 var type = typeof (CustomAttributes); 4 5 var fieldInfo = type.GetField("Address"); 6 if (fieldInfo == null) 7 { 8 return null; 9 } 10 11 var attribute = fieldInfo.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); 12 13 if (attribute == null) 14 { 15 return null; 16 } 17 18 return ((NameAttribute) attribute).Name; 19 }
上面代码就是获取Address字段头部上的Attribute值了。虽然我们是获取到了我们想要的,但是我们发现这样做是不是太累了,如果又扩展一个自定义的Attribute,或者又在一个新的属性或字段上标上Attribute时,我们又要写一段代码来实现我想要的,这些严重代码违反了DRY的设计原则。我们知道获取Attribute是通过反射来取的,Attribute那个值又是不变的,这样就没必要每次都要进行反射来获取了。基于以上两点代码进行了如下的优化,优化后的代码如下:
1 public static class CustomAttributeHelper 2 { 3 /// <summary> 4 /// Cache Data 5 /// </summary> 6 private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>(); 7 8 /// <summary> 9 /// 获取CustomAttribute Value 10 /// </summary> 11 /// <typeparam name="T">Attribute的子类型</typeparam> 12 /// <param name="sourceType">头部标有CustomAttribute类的类型</param> 13 /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param> 14 /// <returns>返回Attribute的值,没有则返回null</returns> 15 public static string GetCustomAttributeValue<T>(this Type sourceType, Func<T, string> attributeValueAction) where T : Attribute 16 { 17 return GetAttributeValue(sourceType, attributeValueAction, null); 18 } 19 20 /// <summary> 21 /// 获取CustomAttribute Value 22 /// </summary> 23 /// <typeparam name="T">Attribute的子类型</typeparam> 24 /// <param name="sourceType">头部标有CustomAttribute类的类型</param> 25 /// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param> 26 /// <param name="name">field name或property name</param> 27 /// <returns>返回Attribute的值,没有则返回null</returns> 28 public static string GetCustomAttributeValue<T>(this Type sourceType, Func<T, string> attributeValueAction, 29 string name) where T : Attribute 30 { 31 return GetAttributeValue(sourceType, attributeValueAction, name); 32 } 33 34 private static string GetAttributeValue<T>(Type sourceType, Func<T, string> attributeValueAction, 35 string name) where T : Attribute 36 { 37 var key = BuildKey(sourceType, name); 38 if (!Cache.ContainsKey(key)) 39 { 40 CacheAttributeValue(sourceType, attributeValueAction, name); 41 } 42 43 return Cache[key]; 44 } 45 46 /// <summary> 47 /// 缓存Attribute Value 48 /// </summary> 49 private static void CacheAttributeValue<T>(Type type, 50 Func<T, string> attributeValueAction, string name) 51 { 52 var key = BuildKey(type, name); 53 54 var value = GetValue(type, attributeValueAction, name); 55 56 lock (key + "_attributeValueLockKey") 57 { 58 if (!Cache.ContainsKey(key)) 59 { 60 Cache[key] = value; 61 } 62 } 63 } 64 65 private static string GetValue<T>(Type type, 66 Func<T, string> attributeValueAction, string name) 67 { 68 object attribute = null; 69 if (string.IsNullOrEmpty(name)) 70 { 71 attribute = 72 type.GetCustomAttributes(typeof (T), false).FirstOrDefault(); 73 } 74 else 75 { 76 var propertyInfo = type.GetProperty(name); 77 if (propertyInfo != null) 78 { 79 attribute = 80 propertyInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault(); 81 } 82 83 var fieldInfo = type.GetField(name); 84 if (fieldInfo != null) 85 { 86 attribute = fieldInfo.GetCustomAttributes(typeof (T), false).FirstOrDefault(); 87 } 88 } 89 90 return attribute == null ? null : attributeValueAction((T) attribute); 91 } 92 93 /// <summary> 94 /// 缓存Collection Name Key 95 /// </summary> 96 private static string BuildKey(Type type, string name) 97 { 98 if (string.IsNullOrEmpty(name)) 99 { 100 return type.FullName; 101 } 102 103 return type.FullName + "." + name; 104 } 105 }
以上优化后的代码:
把不同的代码用泛型T,Fun<T,stirng>来处理来减少重复的代码;
把取过的Attribute值存到一个Dictionary中,下次再来取时,如果有则直接返回Dictionary中的值,如果没有才通过反射来取相应的Attribute值,这样大大的提高效率;
调用方法也更加的简单了,代码如下:
1 var cName=typeof(CustomAttributes).GetCustomAttributeValue<NameAttribute>(x => x.Name); 2 var fName = typeof (CustomAttributes).GetCustomAttributeValue<NameAttribute>(x => x.Name, "Address");
有没有, 是不是很简单,而且调用方式对缓存是完全透明的!