上面代码就是获取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");
有没有, 是不是很简单,而且调用方式对缓存是完全透明的!