C#自定義Attribute值的獲取與優化


  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的類

[Description("Customer Information")]
[Name("customer_info")]
public class CustomerInfo
{
    [Name("name")]
    public string Name { get; set; }

    [Name("address")]
    public string Address;
}

 

  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 using System;
 2 using System.Collections.Concurrent;
 3 using System.Reflection;
 4 
 5 public static class CustomAttributeExtensions
 6 {
 7     /// <summary>
 8     /// Cache Data
 9     /// </summary>
10     private static readonly ConcurrentDictionary<string, object> Cache = new ConcurrentDictionary<string, object>();
11 
12     /// <summary>
13     /// 獲取CustomAttribute Value
14     /// </summary>
15     /// <typeparam name="TAttribute">Attribute的子類型</typeparam>
16     /// <typeparam name="TReturn">TReturn的子類型</typeparam>
17     /// <param name="sourceType">頭部標有CustomAttribute類的類型</param>
18     /// <param name="attributeValueAction">取Attribute具體哪個屬性值的匿名函數</param>
19     /// <returns>返回Attribute的值,沒有則返回null</returns>
20     public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction)
21         where TAttribute : Attribute
22     {
23         return _getAttributeValue(sourceType, attributeValueAction, null);
24     }
25 
26     /// <summary>
27     /// 獲取CustomAttribute Value
28     /// </summary>
29     /// <typeparam name="TAttribute">Attribute的子類型</typeparam>
30     /// <typeparam name="TReturn">TReturn的子類型</typeparam>
31     /// <param name="sourceType">頭部標有CustomAttribute類的類型</param>
32     /// <param name="attributeValueAction">取Attribute具體哪個屬性值的匿名函數</param>
33     /// <param name="propertyName">field name或property name</param>
34     /// <returns>返回Attribute的值,沒有則返回null</returns>
35     public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction, string propertyName)
36         where TAttribute : Attribute
37     {
38         return _getAttributeValue(sourceType, attributeValueAction, propertyName);
39     }
40 
41     #region private methods
42 
43     private static TReturn _getAttributeValue<TAttribute, TReturn>(Type sourceType, Func<TAttribute, TReturn> attributeFunc, string propertyName)
44         where TAttribute : Attribute
45     {
46         var cacheKey = BuildKey<TAttribute>(sourceType, propertyName);
47         var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName));
48         if (value is TReturn) return (TReturn)Cache[cacheKey];
49         return default(TReturn);
50     }
51 
52     private static string BuildKey<TAttribute>(Type type, string propertyName) where TAttribute : Attribute
53     {
54         var attributeName = typeof(TAttribute).FullName;
55         if (string.IsNullOrEmpty(propertyName))
56         {
57             return type.FullName + "." + attributeName;
58         }
59 
60         return type.FullName + "." + propertyName + "." + attributeName;
61     }
62 
63     private static TReturn GetValue<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> attributeValueAction, string name)
64         where TAttribute : Attribute
65     {
66         TAttribute attribute = default(TAttribute);
67         if (string.IsNullOrEmpty(name))
68         {
69             attribute = type.GetCustomAttribute<TAttribute>(false);
70         }
71         else
72         {
73             var propertyInfo = type.GetProperty(name);
74             if (propertyInfo != null)
75             {
76                 attribute = propertyInfo.GetCustomAttribute<TAttribute>(false);
77             }
78             else
79             {
80                 var fieldInfo = type.GetField(name);
81                 if (fieldInfo != null)
82                 {
83                     attribute = fieldInfo.GetCustomAttribute<TAttribute>(false);
84                 }
85             }
86         }
87 
88         return attribute == null ? default(TReturn) : attributeValueAction(attribute);
89     }
90 
91     #endregion
92 }

  優化后的代碼:

  把不同的代碼用泛型T,Fun<TAttribute,TReturn>來處理來減少重復的代碼;
  把取過的Attribute值存到一個ConcurrentDictionary中,下次再來取時,如果有則直接取ConcurrentDictionary中的值,如果沒有才通過反射來取相應的Attribute值,這樣大大的提高效率;

  調用方法也更加的簡單了,代碼如下:

            var customerInfoName = typeof(CustomerInfo).GetCustomAttributeValue<NameAttribute, string>(x => x.Name);
            var customerAddressName = typeof(CustomerInfo).GetCustomAttributeValue<NameAttribute, string>(x => x.Name, "Address");
            var customerInfoDesc = typeof(CustomerInfo).GetCustomAttributeValue<DescriptionAttribute, string>(x => x.Description);

            Console.WriteLine("CustomerInfo Name:" + customerInfoName);
            Console.WriteLine("customerInfo >Address Name:" + customerAddressName);
            Console.WriteLine("customerInfo Desc:" + customerInfoDesc);

  運行結果:

     

  如果你有什么好的或不好的意見歡迎拍磚!

  謝謝大家的建議,己經更新(2019/11/21)

  Code:Download


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM