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

内容目录

一、概述二、反射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. springcloud(四):应用配置中心config的安全设置

    springcloud应用配置中心config的安全设置 在springcloud应用开发中,为了方便在线管理我们的配置文件,通常会配一个配置中心config-server,这里托管着应用的一些配置文 ...

  2. Spring boot 集成 Druid 数据源

    Druid是阿里开源的一个JDBC应用组件,其中包括三部分: DruidDriver:代理Driver,能够提供基于Filter-Chain模式的插件体系. DruidDataSource:高效可管理 ...

  3. elk安装和使用

    elk安装和使用 使用的版本都是5.2.0 elasticsearch-5.2.0安装 在官网 下载 elasticsearch tar包 解压安装 tar zxf elasticsearch-5.2 ...

  4. Django--路由层、视图层、模版层

    路由层: 路由匹配 url(正则表达式,视图函数内存地址) 只要正则匹配到了内容,就不再往下匹配,而是直接运行后面的视图函数 匹配首页) url(r'^&', home) 匹配尾页 url(r ...

  5. ios 把数组对象转成json字符串存起来

    1第一步是我们获取数据源 一般我们都是从接口请求数据 NSArray *subColumnsArray = nil; NSDictionary *dict = [NSJSONSerialization ...

  6. python里面的xlrd模块详解

    那我就一下面积个问题对xlrd模块进行学习一下: 1.什么是xlrd模块? 2.为什么使用xlrd模块? 3.怎样使用xlrd模块? 1.什么是xlrd模块? ♦python操作excel主要用到xl ...

  7. java数据结构——二叉树(BinaryTree)

    前面我们已经学习了一些线性结构的数据结构和算法,接下来我们开始学习非线性结构的内容. 二叉树 前面显示增.删.查.遍历方法,完整代码在最后面. /** * 为什么我们要学习树结构. * 1.有序数组插 ...

  8. 从CAP到zookeeper和eureka对比

    今天看了一篇eureka对比zookeeper的文章,对zookeeper满足CAP中的CP,eureka满足AP产生了一点疑问,故写此篇文章进行一些探讨. 首先我们来看看CAP的定义 Consist ...

  9. 2018年秋招总结篇(Java)

    博主开始找工作是10月10号,感觉可以出去找找工作,然后就去了,参加了多场面试.笔试,现在总结一下 1.笔试篇 String StringBuffer StringBuilder的区别? HashMa ...

  10. Postman 之 HTTP Multipart/form-data 调试

    无论是前端,还是后端开发,HTTP 接口的使用率实在是太高了.开发好了特定的 HTTP 接口,没有一个好的测试工具,怎么可以呢? 而 Postman 就是一款好用的爱不释手的测试工具,谁用谁说爽. 接 ...