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

内容目录

一、概述二、反射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. NetCore下的HTTP请求IHttpClientFactory

    使用方式 IHttpClientFactory有四种模式: 基本用法 命名客户端 类型化客户端 生成的客户端 基本用法 在 Startup.ConfigureServices 方法中,通过在 ISer ...

  2. Linux 中 /proc/meminfo 的含义

    做嵌入式开发对内存泄露很敏感,而对泄露的位置更加关注.本文记录一下从网上搜集的/proc/meminfo各参数的含义.还不完整,待补完. 本文地址:https://segmentfault.com/a ...

  3. 使用Nginx实现反向代理过程(一台服务器部署两个网站)

    正向代理指的是客户端的 反向代理指的是服务端的 需要实现的反向代理: 1.首先使用SwitchHosts配置不同域名,如下:(SwitchHosts软件在上一篇博客有链接) 2.在Linux上部署两台 ...

  4. Spring错误

    今天在学习spring的aop操作时碰到了一个问题: Caused by: org.springframework.aop.framework.AopConfigException: Cannot p ...

  5. Java并发笔记——单例与双重检测

    单例模式可以使得一个类只有一个对象实例,能够减少频繁创建对象的时间和空间开销.单线程模式下一个典型的单例模式代码如下: ① class Singleton{ private static Single ...

  6. 误删除系列一:linux的bin目录误删除后恢复操作

    感言:一失足成千古恨,一不小心就把/usr/bin下所有的命令都删除了,当你以为自己很熟练时,当你以为自己操作对时,可能就是失手的时候,还好这次只是一个测试环境....God 恢复过程:(以下是在vs ...

  7. react navigation goBack()返回到任意页面(不集成redux) 二

    实现思路: A -- > B (获取A的key值,传至C)-- >C(获取B传来的A页面key值,传至D) -- >D(获取C传来的A页面key值&C页面的key值,传至下一 ...

  8. 语音信号的梅尔频率倒谱系数(MFCC)的原理讲解及python实现

    梅尔倒谱系数(MFCC) 梅尔倒谱系数(Mel-scale FrequencyCepstral Coefficients,简称MFCC).依据人的听觉实验结果来分析语音的频谱, MFCC分析依据的听觉 ...

  9. .NET Conf 2019日程(北京时间)

    一年一度的 .NET Conf马上就要开始了,我将日程简易的翻译了一下,并且时间全部转换为北京时间,以方便国内.NETer. 日程 第1天 (北京时间9月24日) .NET Conf 2019 基调 ...

  10. Asp.Net Core2.2 源码阅读系列——控制台日志源码解析

      为了让我们第一时间知道程序的运行状态,Asp.Net Core 添加了默认的日志输出服务.这看起来并没有什么问题,对于开发人员也相当友好,但如果不了解日志输出的细节,也有可能因为错误的日志级别配置 ...