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

内容目录

一、概述二、反射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. 运维核心基础知识之——MD5sum校验文件

    如何使用MD5sum工具校验你的文件. 演示过程截图: 先给文件创建一个md5值 md5sum oldboy.txt 然后将md5sum生成的md5值写入到一个文件police.log md5sum ...

  2. 把windows下的压缩包放到Linux目录下去

    今天在自学redis时出现了问题,因为楼主linux也是空白纸,前几天安装了Linux后就只会基本的命令,其他的一概不通啊,所以当redis要在Linux中用时就傻眼了,索性就在windows中下载了 ...

  3. android 之图片异步加载

    一.概述 本文来自"慕课网" 的学习,只是对代码做一下分析 图片异步加载有2种方式:  (多线程/线程池) 或者 用其实AsyncTask , 其实AsyncTask底层也是用的多 ...

  4. 一次误用CSRedisCore引发的redis故障排除经历

    前导 上次Redis MQ分布式改造完成之后, 编排的容器稳定运行了一个多月,昨天突然收到ETL端同事通知,没有采集到解析日志了. 赶紧进服务器看了一下,用于数据接收的receiver容器挂掉了, 尝 ...

  5. laravel中利用循环实现隔行换色

    1.首先在你的路由文件定义好访问的路径 2. <!doctype html><html lang="en"><head> <meta ch ...

  6. 记一次神奇的sql查询经历,group by慢查询优化

    一.问题背景 现网出现慢查询,在500万数量级的情况下,单表查询速度在30多秒,需要对sql进行优化,sql如下: 我在测试环境构造了500万条数据,模拟了这个慢查询. 简单来说,就是查询一定条件下, ...

  7. Vuex,从入门到...

    Vuex 是什么? 官方是这么说的:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 不懂? ...

  8. 给Xshell增加快速命令集

    一.显示快速命令栏 二.配置快速命令集 在工具中找到快速命令集 添加快速命令集 三.使用快速命令集

  9. CDH集群安装

    1 软硬件准备 1.1 准备三个节点 序号 主机名 内存 CPU IP地址 角色 1 cdh1 8G 8核心 192.168.5.78 cloudera-scm-server,mysql 2 cdh2 ...

  10. go语言-最大32位数反转

    package main import ( "fmt" "strconv" ) func fanzhuang32(number int) string { fu ...