.NET?Core?特性(Attribute)底層原理解析
Attribute的使用場景
Attribute不僅僅局限于C#中,在整個.NET框架中都提供了非常大的拓展點(diǎn),任何地方都有Attribute的影子
- 編譯器層
比如 Obsolete,Conditional - C#層
GET,POST,Max,Range,Require - CLR VM層
StructLayout,DllImport - JIT 層
MethodImpl
Attribute在C#中的調(diào)用
舉個常用的例子,讀取枚舉上的自定義特性。
public enum Test { [EnumDescription("hhhhhh")] None = 0, [EnumDescription("xxxxxx")] Done =1 } private static IEnumerable<string> GetEnumDescriptions(this Enum e) { IEnumerable<string> result = null; var type = e.GetType(); var fieldInfo = type.GetField(e.ToString()); var attr = fieldInfo?.GetCustomAttributes(typeof(EnumDescriptionAttribute), false); if (attr?.Length > 0) { result = attr.Cast<EnumDescriptionAttribute>().Select(x => x.Description); } return result ?? Enumerable.Empty<string>(); }
可以看到,Attribute底層在C#中實現(xiàn)依舊是依賴反射,所以為什么說Attribute是寫給代碼看的注釋,因此對反射的優(yōu)化思路也可以用在Attribute中。
比如在代碼中,使用Dictionary緩存結(jié)果集。避免過多調(diào)用反射造成的性能問題。
private static IEnumerable<string> GetEnumDescriptionsCache(this Enum e) { var key = $"{e.GetType().Name}_{e.ToString()}"; if (_enumMap.ContainsKey(key)) { return _enumMap[key]; } else { var result = GetEnumDescriptions(e); _enumMap.TryAdd(key, result); return result; } }
循環(huán)100000次造成的性能差距還是很明顯的
Newtonsoft.Json對Attrubute的使用
以JsonConverter為藍(lán)本舉例說明。
public class Person { [JsonConverter(typeof(DateTimeConverter))] public DateTime CreateTime { get; set; } } public class DateTimeConverter : JsonConverter<DateTime> { public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.Value == null) return DateTime.MinValue; if (DateTime.TryParse(reader.Value.ToString(), out DateTime result)) return result; return DateTime.MinValue; } public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) { writer.WriteValue(value.ToString("yyyy-MM-dd HH:mm:ss")); } }
定義了一個Attribute:JsonConverter.其底層調(diào)用如下:
[RequiresUnreferencedCode(MiscellaneousUtils.TrimWarning)] [RequiresDynamicCode(MiscellaneousUtils.AotWarning)] public static JsonConverter? GetJsonConverter(object attributeProvider) { // 底層還是調(diào)用Reflection,為了性能,也緩存了對象元數(shù)據(jù)。 JsonConverterAttribute? converterAttribute = GetCachedAttribute<JsonConverterAttribute>(attributeProvider); if (converterAttribute != null) { Func<object[]?, object> creator = CreatorCache.Instance.Get(converterAttribute.ConverterType); if (creator != null) { return (JsonConverter)creator(converterAttribute.ConverterParameters); } } return null; }
Attribute在CLR上的調(diào)用
public class NativeMethods { [DllImport("xxxxx", EntryPoint = "add", CallingConvention = CallingConvention.Cdecl)] public extern static int ManagedAdd(int a, int b); }
在CLR中,同樣用來調(diào)用 C/C++ 的導(dǎo)出函數(shù)。有興趣的朋友可以使用windbg查看線程調(diào)用棧。以及在MetaData中有一張ImplMap表,存儲著C#方法與C++函數(shù)的mapping關(guān)系
Attribute在JIT上的調(diào)用
public class Person { public int id { get; set; } = 0; [MethodImpl(MethodImplOptions.Synchronized)] public void SyncMethod() { id++; } }
JIT會自動為該Attribute注入同步代碼
其本質(zhì)就是注入lock同步塊代碼,只是顆粒度在整個方法上。相對比較大
結(jié)論
Attrubute在C#層面,底層使用反射。因此使用自定義Attribute時,酌情使用緩存來提高性能
到此這篇關(guān)于.NET Core 特性(Attribute)底層原理淺談的文章就介紹到這了,更多相關(guān).NET Core 底層原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
.NET使用結(jié)構(gòu)體替代類提升性能優(yōu)化的技巧
這篇文章主要介紹了.NET使用結(jié)構(gòu)體替代類提升性能優(yōu)化的技巧,使用結(jié)構(gòu)體替代類有什么好處呢?在什么樣的場景需要使用結(jié)構(gòu)體來替代類呢?今天的文章為大家一一解答,需要的朋友可以參考下2022-05-05asp.net下模態(tài)對話框關(guān)閉之后繼續(xù)執(zhí)行服務(wù)器端代碼的問題
asp.net下模態(tài)對話框關(guān)閉之后繼續(xù)執(zhí)行服務(wù)器端代碼的問題...2007-04-04.net core EF Core調(diào)用存儲過程的方式
這篇文章主要給大家介紹了關(guān)于.net core EF Core調(diào)用存儲過程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用.net core EF Core具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05淺談Asp.Net母版頁和內(nèi)容頁運(yùn)行機(jī)制
這篇文章主要介紹了淺談Asp.Net母版頁和內(nèi)容頁運(yùn)行機(jī)制,詳細(xì)的介紹了母版頁和內(nèi)容頁的運(yùn)行過程步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11