.NET Core 特性(Attribute)底层原理浅谈
简介

烂大街的资料不再赘述,简单来说就是给代码看的注释
Attribute的使用场景
Attribute不仅仅局限于C#中,在整个.NET框架中都提供了非常大的拓展点,任何地方都有Attribute的影子
- 编译器层
比如 Obsolete,Conditional - C#层
GET,POST,Max,Range,Require - CLR VM层
StructLayout,DllImport - JIT 层
MethodImpl
Attribute在C#中的调用
举个常用的例子,读取枚举上的自定义特性。
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#中实现依旧是依赖反射,所以为什么说Attribute是写给代码看的注释,因此对反射的优化思路也可以用在Attribute中。
比如在代码中,使用Dictionary缓存结果集。避免过多调用反射造成的性能问题。
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;
}
}
循环100000次造成的性能差距还是很明显的
Newtonsoft.Json对Attrubute的使用
以JsonConverter为蓝本举例说明。
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.其底层调用如下:
[RequiresUnreferencedCode(MiscellaneousUtils.TrimWarning)]
[RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
public static JsonConverter? GetJsonConverter(object attributeProvider)
{
// 底层还是调用Reflection,为了性能,也缓存了对象元数据。
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上的调用
public class NativeMethods
{
[DllImport("xxxxx", EntryPoint = "add", CallingConvention = CallingConvention.Cdecl)]
public extern static int ManagedAdd(int a, int b);
}
在CLR中,同样用来调用 C/C++ 的导出函数。有兴趣的朋友可以使用windbg查看线程调用栈。以及在MetaData中有一张ImplMap表,存储着C#方法与C++函数的mapping关系
Attribute在JIT上的调用
public class Person
{
public int id { get; set; } = 0;
[MethodImpl(MethodImplOptions.Synchronized)]
public void SyncMethod()
{
id++;
}
}
JIT会自动为该Attribute注入同步代码


其本质就是注入lock同步块代码,只是颗粒度在整个方法上。相对比较大
结论
Attrubute在C#层面,底层使用反射。因此使用自定义Attribute时,酌情使用缓存来提高性能
.NET Core 特性(Attribute)底层原理浅谈的更多相关文章
- CSRF漏洞原理浅谈
CSRF漏洞原理浅谈 By : Mirror王宇阳 E-mail : mirrorwangyuyang@gmail.com 笔者并未深挖过CSRF,内容居多是参考<Web安全深度剖析>.& ...
- Java线上问题排查神器Arthas快速上手与原理浅谈
前言 当你兴冲冲地开始运行自己的Java项目时,你是否遇到过如下问题: 程序在稳定运行了,可是实现的功能点了没反应. 为了修复Bug而上线的新版本,上线后发现Bug依然在,却想不通哪里有问题? 想到可 ...
- 如何把Java代码玩出花?JVM Sandbox入门教程与原理浅谈
在日常业务代码开发中,我们经常接触到AOP,比如熟知的Spring AOP.我们用它来做业务切面,比如登录校验,日志记录,性能监控,全局过滤器等.但Spring AOP有一个局限性,并不是所有的类都托 ...
- JAVA CAS原理浅谈
java.util.concurrent包完全建立在CAS之上的,没有CAS就不会有此包.可见CAS的重要性. CAS CAS:Compare and Swap, 翻译成比较并交换. java.uti ...
- CAS+SSO原理浅谈
http://www.cnblogs.com/yonsin/archive/2009/08/29/1556423.htmlSSO 是一个非常大的主题,我对这个主题有着深深的感受,自从广州 UserGr ...
- Mysql锁原理浅谈
锁类型/引擎 行锁 表锁 页锁 MyISAM 有 InnoDB 有 有 BDB(被InnoDB取代) 有 有 锁的分类 表锁:开销小,加锁快,不会死锁,粒度大,冲突率高,并发低. 行锁:开销大,加锁慢 ...
- php模板原理PHP模板引擎smarty模板原理浅谈
mvc是开发中的一个伟大的思想,使得开发代码有了更加清晰的层次,让代码分为了三层各施其职.无论是对代码的编写以及后期的阅读和维护,都提供了很大的便利. 我们在php开发中,视图层view是不允许有ph ...
- PHP的模板引擎smarty原理浅谈
mvc是开发中的一个伟大的思想,使得开发代码有了更加清晰的层次,让代码分为了三层各施其职.无论是对代码的编写以及后期的阅读和维护,都提供了很大的便利. 我们在php开发中,视图层view是不允许有ph ...
- Docker 基础底层架构浅谈
docker学习过程中,免不了需要学习下docker的底层技术,今天我们来记录下docker的底层架构吧! 从上图我们可以看到,docker依赖于linux内核的三个基本技术:namespaces.C ...
- Java中的SPI原理浅谈
在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则& ...
随机推荐
- c# 复制文件夹内所有文件到另外一个文件夹
/// <summary> /// 开始转移 /// </summary> /// <param name="sender"></para ...
- Unrecognized SSL message, plaintext connection?
报错:Unrecognized SSL message, plaintext connection? 修改:把 requestContext.setScheme(Scheme.HTTPS);修改为 r ...
- CSS单位em、rem、vh和vw等及CSS3的calc()以及line-height百分比
css单位我们常用的是px,也即是像素.随着网页开发自适应的要求,css3新增了许多单位,rem.vw和vh.vmin和vmax.ch和ex等. em 做前端的应该对em不陌生,不是什么罕见的单位,是 ...
- nacos未授权访问漏洞,导致被网警找
背景 公司收购了另一家公司,所以相应的后端服务和服务器都交给我管理,但是没有任何的交接文档,大概看了一下代码,依赖的东西就去忙别的了. 直到今天网警突然打电话给我说系统有漏洞(CVE-2021-294 ...
- ASP.NET Core – Custom Input formatters For Partial Update and Handle Under-posting
前言 之前的文章有谈过关于 ASP.NET Core 处理 under-posting 的方式. 它会使用 class default value. 许多时候这可能不是我们期望的. 比如当我们想要 p ...
- Servlet—— urlPattern配置
Servlet urlPattern配置 Servlet要想被访问,必须配置其访问路径(urlPattern) 1.一个Servlet可以配置多个 urlPattern 2.ur ...
- QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口?
QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口? 简介 本文介绍了QT6窗口系统中的QT底层窗口 ...
- go语言中变量的作用域
Go 语言中的变量作用域规则决定了变量在程序的哪些部分是可见的和可以访问的.理解这些规则对于编写清晰.维护性高的代码非常重要.下面是一个系统性的解释. 变量的作用域类型 包级作用域: 包级作用域的变量 ...
- window10任务栏图标不见了(如何修复)
1.按 Windows键+ R 2.写 %temp% 在其中,然后单击"确定". 3.删除其中的所有内容以清除临时文件. 4.重启
- 2023年第十二届数据技术嘉年华(DTC)资料分享
第十二届数据技术嘉年华(DTC 2023)已于4月8日在北京圆满落幕,大会围绕"开源·融合·数智化--引领数据技术发展,释放数据要素价值"这一主题,共设置有1场主论坛,12场专题论 ...
