来源: 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");
有没有, 是不是很简单,而且调用方式对缓存是完全透明的!
Mikel
