知识需要不断积累、总结和沉淀,思考和写作是成长的催化剂

内容目录

一、概述二、反射1、反射使用2、创建对象3、调用方法4、字段属性三、特性四、总结

一、概述

反射其实无处不在,我们用VS进行调试时候,查看成员列表、修改变量值都是通过反射来实现的。我们写业务代码可能很少去写反射,但理解反射是从菜鸟到大牛的必经之路。无论EF还是ASP.NET,几乎所有框架都用到反射。反射动态创建对象、动态赋值、动态调用方法

前面简单介绍过.NET的第一次编译,会编译成IL(中间语言),反射就是利用IL在运行时获取类的各种信息(字段、方法、构造函数等),并且可以动态的创建对象调用方法。反射就是通过使用metadata的过程

每一个类对应有一个Type对象,方法对应一个MethodInfo对象,属性对应一个PropertyInfo,这些都是一个类的元数据(MetaData)保存在IL中,所以解析IL可以获取一个类的各种信息。

特性就和反射绑定的,没有反射,特性就无从使用。特性本质就是给类、方法等元素添加一些额外的信息和行为。特性添加编译后也产生IL,我们没法直接使用的,只在MetaData中有记录,我们只能用过反射得到。

二、反射

1、反射使用

使用System.Reflection。.Net框架提供帮助类库来进行反射。通常像下面这样使用,加载绝对/相对路径下的dll。(注意加载某一个dll,它内部依赖于别的类库,需要把它们都放在统一路径下)

Type的获取,可以从对象获取,类名获取或类全路径获取(通过配置项实例化类很方便)。Activator.CreateInstance(type)创建类实例。加载dll创建某个实例用的都只是字符串,既然是字符串那么就可以放在配置中。像下面这种如果要换个国家的人来打招呼就需要替换红色字符即可。(前提当然是每个国家的人都继实现ISayHello打招呼接口)。依赖于具体类型改为依赖字符配置文件了

最常用的还是数据库访问层的封装,不同数据库的访问都实现IDBHelper接口,如果换不同类型的数据库,就只需要修改配置文件即可。

2、创建对象

上面通过反射仅调用无参数构造函数,那么有参数的呢。像下面这样,给个object[]数组指定参数。

另外需要注意反射创建对象可以调用私有的构造函数,这意味着它可以对单例模式造成破坏。(单例模式在设计模式中会详细了解,就是一个类全局只有一个实例)。具体看下面实例对比。

还有一种泛型类型的反射创建比较特殊。假设有以下泛型类,那么在GetType时候需要使用“`”(反单引号)占位符,这个符号键盘上一般在ESC键下方或数字1键的左边。后接数字表示需要多少个泛型类型,然后指定具体的类型通过MakeGenericType再次创建出Type。

后面在容器里会看到,IOC类型创建都是利用反射通过注解扫描或配置

3、调用方法

像下面注释说明的那样,包括类的私有方法也可以反射调用。泛型方法和泛型类的创建类似,需要在获取指定名称泛型方法基础上,用类型数组代替泛型方法类型参数

方法也可以通过字符指定,虽然调用起来比较麻烦,但的确很灵活。像MVC框架里URL的映射就是利用类名+方法名来调用后台的

4、字段属性

字段和属性的获取也类似。通过GetFields、GetProperties获取。

三、特性

Attribute特性标签,也被叫做注解,用来给我们的类、属性、方法等附加一些元信息,这些信息一般不影响我们代码的实际逻辑,起辅助作用,给框架或编译器去解析的。通过Type对象仍然可以轻松获取注解对象。表格中的内置注解我们不陌生

特性 说明
[Obsolete] 表明此成员已过时
[ReadOnly(true)] 在编辑器中只读,代码赋值不受影响
[DisplayName("姓名")] 属性的显示名
[Browsable(false)] 属性是否可见
[Serializable] 序列化和反序列化

除了.NET框架内置的特性,我们通过继承Attribute可以自定义一个特性。例子中AttributeUsage是专用于标注自定义特性的特性,可以指定该特性的作用目标是类、方法还是字段等,AllowMultiple允许同一个元素上可以多重标记该特性。

使用特性时,像下面这样。在需要标记的元素上用总括号包裹特性类。语法类似调用构造函数,先是构造函数的参数(有参、无参),然后可以命名赋值属性。

编码时标记的特性,不去调用,只直观的看,是没有什么意思的。通过反编译工具ILSpy查看IL代码,会发现在每个加了特性的元素(类、属性、方法等)处会生成特性类型的构造函数。既然在IL中存在构造函数,那我们就可以通过反射直接创建类实例。

我们会有一个整体感觉,特性就是给类、属性、方法等元素添加一个额外的、补充的描述,而没有破坏原有类的封装。像实体类属性上的数据的规范性检查特性一样,我们可以定制统一的属性检查特性类,然后编码中只需要在需要检查的属性上加上特性标记即可。通过反射就可以轻松获取这些补充信息,大概像下面这样,我们对object类型增加Validate扩展方法,这样所有的类型都可以调用这个扩展方法,然后通过反射查找类型内部是否标记有需要验证的属性。

类似还有枚举的别名描述,字典项指等。获取某一枚举的中文别名描述信息或实体类中某一个字段和数据库表对应的列名(不一致时)。

四、总结

反射意味着动态。面向对象开发,对象之间协同完成某一功能,本身应该算耦合的,修改一个,其他依赖都需要修改,反射就可以把依赖抽象,依赖于扩展,运行时动态构建对象去完成某一功能,使其更加灵活,常见的插件开发和IOC容器就是典型应用。但反射也有缺点,就是写起来复杂,而且因为是动态的,避开了编译器的检查,性能也肯定不如硬编码,这种性能我们大可不用太担心,因为影响程序性能占比最大的应该还是我们本身的编码设计能力。

特性是和反射绑定的。.NET框架内置了很多特性,我们可能用不到自己手写特性,但明白其中的原理是必要的,在Bs开发中,wcf、mvc等都用到特性注解。Java Web中Spring MVC也是通过注解来扫描装配Bean的。特性和注释可是完全不同的,注释就是给人看,对程序一点影响都没有,特性可以影响程序的运行。

如果手机在手边,也可以关注下vx:xishaobb,互动或获取更多消息。当然这里也一直更新de。

.NET进阶篇03-Reflection反射、Attribute特性的更多相关文章

  1. MySQL进阶篇(03):合理的使用索引结构和查询

    本文源码:GitHub·点这里 || GitEE·点这里 一.高性能索引 1.查询性能问题 在MySQL使用的过程中,所谓的性能问题,在大部分的场景下都是指查询的性能,导致查询缓慢的根本原因是数据量的 ...

  2. 02:Django进阶篇

    目录:Django其他篇 01:Django基础篇 02:Django进阶篇 03:Django数据库操作--->Model 04: Form 验证用户数据 & 生成html 05:Mo ...

  3. 02: tornado进阶篇

    目录:Tornado其他篇 01: tornado基础篇 02: tornado进阶篇 03: 自定义异步非阻塞tornado框架 04: 打开tornado源码剖析处理过程 目录: 1.1 自定制t ...

  4. IOC容器特性注入第一篇:程序集反射查找

    学习kooboo的框架发现它的注入容器方法比较特别,同样是利用MVC的注入点,但它是查找网站下面bin所有的DLL利用反射查找特性找到对应的服务注入到容器. 这样的好处很简单:完全可以不用关心IOC容 ...

  5. PHP 进阶篇:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 (麦子学员 第三阶段)

    以下是进阶篇的内容:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 ================================== ...

  6. 关于C# 中的Attribute 特性

    关于C# 中的Attribute 特性 作者: 钢钢  来源: 博客园  发布时间: 2011-01-09 23:30  阅读: 13921 次  推荐: 12   原文链接 [收藏] 摘要:纠结地说 ...

  7. C#反射与特性(七):自定义特性以及应用

    目录 1,属性字段的赋值和读值 2,自定义特性和特性查找 2.1 特性规范和自定义特性 2.2 检索特性 3,设计一个数据验证工具 3.1 定义抽象验证特性类 3.2 实现多个自定义验证特性 3.3 ...

  8. C#反射与特性(九):全网最全-解析反射

    目录 1,判断类型 1.1 类和委托 1.2 值类型 1.3 接口 1.4 数组 2, 类型成员 2.1 类 2.2 委托 2.3 接口 [微信平台,此文仅授权<NCC 开源社区>订阅号发 ...

  9. Membership三步曲之进阶篇 - 深入剖析Provider Model

    Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...

随机推荐

  1. 分析spring4和spring5日志中的不同

    日志在工作中起到关键作用,我们经常使用它来打印关键信息,方便分析,或者是输出错误信息,用于bug排查,spring中同样使用了日志进行信息的输出,但是spring4和spring5之间的日志又有些不同 ...

  2. netcore mvc 的简单实现

    实现的功能 简单的路由系统 支持中间件 简单Filter支持 只支持HttpPost.HttpGet 使用Dotliquid做为视图渲染引擎 核心实现 HttpChannel 复制监听Tcp请求,并按 ...

  3. get和post请求方式的区别

    1.用途方面: get是向服务器请求数据,post是向服务器发送数据. 2.大小方面: get发送数据上有大小限制,post理想上无大小限制,实际上有限制. 3.安全方面: get请求的数据会显示在地 ...

  4. Winforn中设置ZedGraph曲线图的属性、坐标轴属性、刻度属性

    场景 C#窗体应用中使用ZedGraph曲线插件绘制图表: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/99716066 在上面 ...

  5. airflow使用本地时区

    ​ 在airflow中使用的时间是utc时间,而更多时候我们希望的是使用本地时间,于是在定义airflow定时任务的时候,涉及到了时间的转换. 1.python中本地时间和utc时间的转换 查看国内可 ...

  6. 01 jvm学习过程概述

    声明:本博客仅仅是一个初学者的学习记录.心得总结,其中肯定有许多错误,不具有参考价值,欢迎大佬指正,谢谢!想和我交流.一起学习.一起进步的朋友可以加我微信Liu__66666666 这是简单学习一遍之 ...

  7. 论文阅读 | DeepDrawing: A Deep Learning Approach to Graph Drawing

    作者:Yong Wang, Zhihua Jin, Qianwen Wang, Weiwei Cui, Tengfei Ma and Huamin Qu 本文发表于VIS2019, 来自于香港科技大学 ...

  8. Docker笔记(十一):Dockerfile详解与最佳实践

    Dockerfile是一个文本文件,包含了一条条指令,每条指令对应构建一层镜像,Docker基于它来构建一个完整镜像.本文介绍Dockerfile的常用指令及相应的最佳实践建议. 1. 理解构建上下文 ...

  9. Python学习-is和==区别, encode和decode

    一.is 和 == 介绍 1. is  比较的是两个对象的内存地址是否相同,它们是不是同一个对象. 2. ==  比较的是两个对象的内容是否相同. 在使用is前,先介绍Python的一个内置函数id( ...

  10. ajax发送PUT请求,使用HttpPutFormContentFilter过滤器接受办法

    相信在使用ajax发送put请求时候,肯定遇到过后端数据无法被接受到的405错误. 为什么会遇到这个问题? 1.首先查看Tomcat源码 关于如何将数据封装到Request public class ...