C#自定義Attribute值的獲取與優(yōu)化技巧
首先說下什么是Atrribute
首先,我們肯定Attribute是一個(gè)類,下面是msdn文檔對(duì)它的描述:
公共語言運(yùn)行時(shí)允許你添加類似關(guān)鍵字的描述聲明,叫做attributes,它對(duì)程序中的元素進(jìn)行標(biāo)注,如類型、字段、方法和屬性等。Attributes和Microsoft .NET Framework文件的元數(shù)據(jù)保存在一起,可以用來向運(yùn)行時(shí)描述你的代碼,或者在程序運(yùn)行的時(shí)候影響應(yīng)用程序的行為。
在.NET中,Attribute被用來處理多種問題,比如序列化、程序的安全特征、防止即時(shí)編譯器對(duì)程序代碼進(jìn)行優(yōu)化從而代碼容易調(diào)試等等。下面,我們先來看幾個(gè)在.NET中標(biāo)準(zhǔn)的屬性的使用,稍后我們?cè)倩剡^頭來討論Attribute這個(gè)類本身。(文中的代碼使用C#編寫,但同樣適用所有基于.NET的所有語言)
Attribute作為編譯器的指令
在C#中存在著一定數(shù)量的編譯器指令,如:#define DEBUG, #undefine DEBUG, #if等。這些指令專屬于C#,而且在數(shù)量上是固定的。而Attribute用作編譯器指令則不受數(shù)量限制。比如下面的三個(gè)Attribute:
Conditional:起條件編譯的作用,只有滿足條件,才允許編譯器對(duì)它的代碼進(jìn)行編譯。一般在程序調(diào)試的時(shí)候使用。
DllImport:用來標(biāo)記非.NET的函數(shù),表明該方法在一個(gè)外部的DLL中定義。
Obsolete:這個(gè)屬性用來標(biāo)記當(dāng)前的方法已經(jīng)被廢棄,不再使用了。
C# Attribute值獲取
C#自定義Attribute值的獲取是開發(fā)中會(huì)經(jīng)常用到的,一般我們的做法也就是用反射進(jìn)行獲取的,代碼也不是很復(fù)雜。
1、首先有如下自定義的Attribute
[AttributeUsage(AttributeTargets.All)] public sealed class NameAttribute : Attribute { private readonly string _name; public string Name { get { return _name; } } public NameAttribute(string name) { _name = name; } }
2、定義一個(gè)使用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"也就很簡(jiǎn)單了
private static string GetName() { var type = typeof(CustomAttributes); var attribute = type.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); if (attribute == null) { return null; } return ((NameAttribute)attribute).Name; }
以上代碼就可以簡(jiǎn)單的獲取,類上的Attribute的值了,但是需求往往不是這么簡(jiǎn)單的,不僅要獲取類頭部Attribute上的值,還要獲取字段Address頭部Attribute上的值。有的同學(xué)可能就覺得這還不簡(jiǎn)單呀,直接上代碼
private static string GetAddress() { var type = typeof (CustomAttributes); var fieldInfo = type.GetField("Address"); if (fieldInfo == null) { return null; } var attribute = fieldInfo.GetCustomAttributes(typeof(NameAttribute), false).FirstOrDefault(); if (attribute == null) { return null; } return ((NameAttribute) attribute).Name; }
上面代碼就是獲取Address字段頭部上的Attribute值了。雖然我們是獲取到了我們想要的,但是我們發(fā)現(xiàn)這樣做是不是太累了,如果又?jǐn)U展一個(gè)自定義的Attribute,或者又在一個(gè)新的屬性或字段上標(biāo)上Attribute時(shí),我們又要寫一段代碼來實(shí)現(xiàn)我想要的,這些嚴(yán)重代碼違反了DRY的設(shè)計(jì)原則。我們知道獲取Attribute是通過反射來取的,Attribute那個(gè)值又是不變的,這樣就沒必要每次都要進(jìn)行反射來獲取了?;谝陨蟽牲c(diǎn)代碼進(jìn)行了如下的優(yōu)化,優(yōu)化后的代碼如下:
using System; using System.Collections.Concurrent; using System.Reflection; public static class CustomAttributeExtensions { /// <summary> /// Cache Data /// </summary> private static readonly ConcurrentDictionary<string, object> Cache = new ConcurrentDictionary<string, object>(); /// <summary> /// 獲取CustomAttribute Value /// </summary> /// <typeparam name="TAttribute">Attribute的子類型</typeparam> /// <typeparam name="TReturn">TReturn的子類型</typeparam> /// <param name="sourceType">頭部標(biāo)有CustomAttribute類的類型</param> /// <param name="attributeValueAction">取Attribute具體哪個(gè)屬性值的匿名函數(shù)</param> /// <returns>返回Attribute的值,沒有則返回null</returns> public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction) where TAttribute : Attribute { return _getAttributeValue(sourceType, attributeValueAction, null); } /// <summary> /// 獲取CustomAttribute Value /// </summary> /// <typeparam name="TAttribute">Attribute的子類型</typeparam> /// <typeparam name="TReturn">TReturn的子類型</typeparam> /// <param name="sourceType">頭部標(biāo)有CustomAttribute類的類型</param> /// <param name="attributeValueAction">取Attribute具體哪個(gè)屬性值的匿名函數(shù)</param> /// <param name="propertyName">field name或property name</param> /// <returns>返回Attribute的值,沒有則返回null</returns> public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction, string propertyName) where TAttribute : Attribute { return _getAttributeValue(sourceType, attributeValueAction, propertyName); } #region private methods private static TReturn _getAttributeValue<TAttribute, TReturn>(Type sourceType, Func<TAttribute, TReturn> attributeFunc, string propertyName) where TAttribute : Attribute { var cacheKey = BuildKey<TAttribute>(sourceType, propertyName); var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName)); if (value is TReturn) return (TReturn)Cache[cacheKey]; return default(TReturn); } private static string BuildKey<TAttribute>(Type type, string propertyName) where TAttribute : Attribute { var attributeName = typeof(TAttribute).FullName; if (string.IsNullOrEmpty(propertyName)) { return type.FullName + "." + attributeName; } return type.FullName + "." + propertyName + "." + attributeName; } private static TReturn GetValue<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> attributeValueAction, string name) where TAttribute : Attribute { TAttribute attribute = default(TAttribute); if (string.IsNullOrEmpty(name)) { attribute = type.GetCustomAttribute<TAttribute>(false); } else { var propertyInfo = type.GetProperty(name); if (propertyInfo != null) { attribute = propertyInfo.GetCustomAttribute<TAttribute>(false); } else { var fieldInfo = type.GetField(name); if (fieldInfo != null) { attribute = fieldInfo.GetCustomAttribute<TAttribute>(false); } } } return attribute == null ? default(TReturn) : attributeValueAction(attribute); } #endregion }
優(yōu)化后的代碼:
把不同的代碼用泛型T,Fun<TAttribute,TReturn>來處理來減少重復(fù)的代碼;
把取過的Attribute值存到一個(gè)ConcurrentDictionary中,下次再來取時(shí),如果有則直接取ConcurrentDictionary中的值,如果沒有才通過反射來取相應(yīng)的Attribute值,這樣大大的提高效率;
調(diào)用方法也更加的簡(jiǎn)單了,代碼如下:
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);
運(yùn)行結(jié)果:
到此這篇關(guān)于C#自定義Attribute值的獲取與優(yōu)化的文章就介紹到這了,更多相關(guān)C# Attribute值獲取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#基礎(chǔ)知識(shí)之base關(guān)鍵字介紹
本文主要介紹base關(guān)鍵字的使用方法,base關(guān)鍵字可以調(diào)用基類重寫的方法,可以調(diào)用基類的構(gòu)造方法,還可以在EntityFramework中使用,下面一一介紹。2016-04-04C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法
這篇文章主要介紹了C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法,詳細(xì)分析了事件推送與消息排重的使用技巧,對(duì)微信開發(fā)有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01C# webservice接口編寫、發(fā)布與測(cè)試
這篇文章主要介紹了C# webservice接口編寫、發(fā)布與測(cè)試,文章通過圖文結(jié)合的方式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或共組有一定的幫助,需要的朋友可以參考下2024-07-07