.NET Core 特性(Attribute)底层原理解析

 更新时间:2024年11月20日 08:53:52   作者:叫我安不理  
Attribute不仅仅局限于C#中,在整个.NET框架中都提供了非常大的拓展点,任何地方都有Attribute的影子,这篇文章主要介绍了.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;
        }

https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/JsonTypeReflector.cs

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)底层原理浅谈的文章就介绍到这了,更多相关.NET Core 底层原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • win2003服务器asp.net权限设置问题及解决方法

    win2003服务器asp.net权限设置问题及解决方法

    ASP.NET相对于ASP,设置权限方面有点不同,有一点儿设置错了都运行不到。在网上搜索到的都是很垃圾的答案,没有一个用得到的,下面是我自己设置并从中遇到的问题摸索后得到的经验,给大家分享。
    2011-08-08
  • ASP.NET 常用 文件上传方法

    ASP.NET 常用 文件上传方法

    文件的上传下载是我们在实际项目开发过程中经常需要用到的技术,这里给出几种常见的方法
    2009-07-07
  • ASP.NET MVC Layout如何嵌套

    ASP.NET MVC Layout如何嵌套

    这篇文章主要为大家详细介绍了ASP.NET MVC Layout如何嵌套,ASP.NET MVC Layout进行嵌套的方法,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • 三种asp.net页面跳转的方法

    三种asp.net页面跳转的方法

    跳转页面是大部编辑语言中都会有的,下面我们来分别介绍一下关于.net中response.redirect sever.execute server.transfer三种页面跳转的方法,,需要的朋友可以参考下
    2015-10-10
  • Excel、记事本数据导入到数据库的实现方法

    Excel、记事本数据导入到数据库的实现方法

    将手机号批量导入数据库。思路:先将要导入的文件传上项目里,然后读取文件的每行数据并插入数据库,操作完后再将上传的文件删除
    2013-10-10
  • 在ASP.NET使用JavaScript显示信息提示窗口实现原理及代码

    在ASP.NET使用JavaScript显示信息提示窗口实现原理及代码

    在ASP.NET使用JavaScript显示信息窗口,感兴趣的朋友可以了解一下,本文将介绍详细的操作步骤,希望对你的JavaScript知识巩固有所帮助
    2013-01-01
  • ASP.NET 主题的简单配置教程

    ASP.NET 主题的简单配置教程

    主题和css差不多但是他可以提供一些css不能提供的特性,下面为大家介绍下ASP.NET 主题的简单配置,感兴趣的朋友不要错过
    2013-12-12
  • 在ASP.NET Core5.0中访问HttpContext的方法步骤

    在ASP.NET Core5.0中访问HttpContext的方法步骤

    这篇文章主要介绍了在ASP.NET Core5.0中访问HttpContext的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • MVC分页之MvcPager使用详解

    MVC分页之MvcPager使用详解

    这篇文章主要为大家详细介绍了MVC分页之MvcPager使用方法,针对MvcPager同步和Ajax异步分页进行讲解,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • ASP.NET 控件开发系列之图片切换web控件

    ASP.NET 控件开发系列之图片切换web控件

    刚开始学习控件开发,写了一个web图片切换控件,欢迎大家拍砖.
    2010-04-04

最新评论