c# 反射专题—————— 介绍一下是什么是反射[ 一]
前言
为什么有反射这个系列,这个系列后,asp net 将会进入深入篇,如果没有这个反射系列,那么asp net的源码,看了可能会觉得头晕,里面的依赖注入包括框架源码是大量的反射。
正文
下面是官方文档的介绍:
https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/reflection
说的比较绕,反射就是用来动态创建对象的。
那么什么是动态创建对象? 动态创建对象就是运行时创建对象。
那么为什么需要动态创建对象呢?
可以思考一下,我们写代码的时候为什么需要动态创建?
这里我举一个例子。
比如说,eventbus,通过不同的字符串反射成不同的事件。
可能有人没怎么接触这个eventbus,再举个例子。
有一个api,用户可以传入动物的名字和该动物的一些属性,那么当我们拿到这些字符串的时候,我们在内部根据动物的名字和属性创建响应的对象。
反射动态创建对象:
static void Main(string[] args)
{
Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集
dynamic obj = assembly.CreateInstance("ConsoleApp7.Cat");
Console.WriteLine(obj);
}

可以看到,我们通过反射创建一个对象。
那么为什么反射能创建一个对象呢? 它的原理是什么呢?
在https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/viewing-type-information 文中写道:
当反射提出请求时,公共语言运行时为已加载的类型创建 Type 。 可使用 Type 对象的方法、字段、属性和嵌套类来查找该类型的任何信息。
也就是说在运行的时候,会为加载的类型,创建Type,那么如何获取Type 呢?
Type catType = Type.GetType("ConsoleApp7.Cat");

那么这里原理也清晰了,原来在.net 运行的时候会为加载的类型创建Type,通过Type 就能创建实例。
那么Type 里面有什么呢? 首先肯定有构造函数吧,不然怎么创建实例呢? 那么还有什么呢?
上文也提及到了里面有方法、字段、属性、嵌套类等用来描述这个类型的信息。
举个例子:比如说我这个Cat 类吧, 在加载的时候会创建Cat的Type,那么这个Type 里面就存有我这个Cat的方法、字段、属性等,这些可以统称为元数据。
元数据也就是metadata:
可以看下下面这篇介绍:
https://baike.baidu.com/item/元数据/1946090?fr=aladdin
元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。
这就是这个Type 就是对加载类型的描述了,有了它那么可以做事情。
例如获取属性,获取方法等。
举个例子:
Type catType = Type.GetType("ConsoleApp7.Cat");
var cat = Activator.CreateInstance(catType);

这个时候有人就问了,为什么c# 不设计成: catType.CreateInstance();
这样获取不是更加简单吗? 这就是c# 的优雅的地方。 Type 是仅仅对类型的描述,这样 Type 就不会随着扩展变得臃肿。不谈这个领域驱动篇马上开始了,这里面会介绍。
那么这里有一个问题了,其实我们反射创建对象也就是为了调用里面方法,那么这个怎么做呢?
比如说调用里面的Cat的Hi 方法?
public class Cat
{
public void Hi()
{
Console.WriteLine("hi master!");
}
}
然后这样写:
static void Main(string[] args)
{
Type catType = Type.GetType("ConsoleApp7.Cat");
var cat = (Cat)Activator.CreateInstance(catType);
cat.Hi();
Console.ReadKey();
}
这样写会运行正常吗? 那肯定能运行正常。

那么我们为什么一般不这样写?这里就有一个问题,我们反射的目的是什么?
是为了动态加载,动态加载是为了动态创建对象? 这显然不是,是为了动态能够执行某段代码,也就是动态运行。
既然我们在运行的时候才知道类型,那么我们是如何能保证知道我们要调用的方法呢?
所以一般这样写:
static void Main(string[] args)
{
Type catType = Type.GetType("ConsoleApp7.Cat");
var cat = (Cat)Activator.CreateInstance(catType);
var hiMethod = catType.GetMethod("Hi");
hiMethod.Invoke(cat, null);
Console.ReadKey();
}
这里不要看我写的是固定ConsoleApp7.Cat 和 Hi,到了真正写代码都是传入参数进去的。

一样的能够运行。
从上面可以看出,其实在反射的眼里,方法也就是对象,通过把Hi 这个方法当成了himethod 这个对象。
可能在c# 中表现的不是很明显,在js 语言中表现的非常明显,方法就是一个对象。
看起来反射挺好用的啊,那么现在反射的优点就是动态加载,那么反射的缺点有吗?
反射的缺点也很明显,那就是执行更慢,为什么会执行更慢呢? 那是因为反射是几乎是边解释边运行的。
为什么反射会边解释边运行呢? 因为他做不到先编译再运行,微软在新的c#版本中做了优化,如何能避免反射,这个后续说明。
下面测试一下性能:
cat 中加入方法:
static void Main(string[] args)
{
Type catType = Type.GetType("ConsoleApp7.Cat");
var cat = Activator.CreateInstance(catType);
var hiMethod = catType.GetMethod("Hi");
Console.WriteLine("反射的运行时间");
Stopwatch stopwatch = Stopwatch.StartNew();
for (var i =0; i<9999999; i++)
{
hiMethod.Invoke(cat, null);
}
stopwatch.Stop();
var elapsed = stopwatch.Elapsed;
Console.WriteLine(elapsed.Milliseconds);
Console.WriteLine("正常创建对象的时间");
Cat cat2 = new Cat();
Stopwatch stopwatch2 = Stopwatch.StartNew();
for (var i = 0; i < 9999999; i++)
{
cat2.Hi();
}
stopwatch2.Stop();
var elapsed2 = stopwatch2.Elapsed;
Console.WriteLine(elapsed2.Milliseconds);
Console.ReadKey();
}
结果:

可以看到相差非常远。
那么既然性能相差这么远,为什么我们还要用反射呢?
这个问题很简单,很多人喜欢拿性能说事,简单的说就是我们做工程的,考虑的是工程角度,性能是是否能满足需求的指标,反射大多数场景还是满足需求的。
那么反射是否可以优化?
可以。 我没有优化过,网上有很多文章,没有遇到过这种场景。
结
这一节只是介绍一下什么是反射,和反射的优缺点,这是一个系列,所以后面大多数是介绍一些反射的api调用 和 原理。以上为个人整理,如有错误望请指点。
很大一部分参考于官方文档: https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection, 只是个人用通俗的语言整理一下。
c# 反射专题—————— 介绍一下是什么是反射[ 一]的更多相关文章
- Java反射详细介绍
反射 目录介绍 1.反射概述 1.1 反射概述 1.2 获取class文件对象的三种方式 1.3 反射常用的方法介绍 1.4 反射的定义 1.5 反射的组成 1.6 反射的作用有哪些 2.反射的相关使 ...
- C#反射机制介绍
反射的定义:审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等. ...
- php反射类的使用及Laravel对反射的使用介绍
PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法.成员,而反射类则是拆封类中的所有方法.成员变量,并包括私有方法等.就如“解刨”一样,我们可以调用任何关键字修饰的方法.成员.当然在正常业 ...
- Android 插件化开发(一):Java 反射技术介绍
写在前面:学习插件化开发推荐书籍<Android 插件化开发指南>,本系列博客所整理知识部分内容出自此书. 在之前的项目架构的博文中,我们提到了项目插件化架构,提到插件化架构不得不提的到J ...
- C++反射机制:可变参数模板实现C++反射
1. 概要 本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在Github ...
- Java反射的理解(六)-- 通过反射了解集合泛型的本质
Java反射的理解(六)-- 通过反射了解集合泛型的本质 上述写了那么多,我们可能会有个疑问,为什么要用反射,步骤比我们常规的加载类操作复杂多了,别急,这个问题我最后才解答,我们先来了解集合泛型的本质 ...
- C++反射机制:可变参数模板实现C++反射(二)
1. 概要 2018年Bwar发布了<C++反射机制:可变参数模板实现C++反射>,文章非常实用,Bwar也见过好几个看了那篇文章后以同样方法实现反射的项目,也见过不少从我的文章抄过去 ...
- Java 反射机制介绍
参考文章:http://www.cnblogs.com/skywang12345/p/3345205.html Java 反射机制.通俗来讲呢,就是在运行状态中,我们可以根据“类的部分已经的信息”来还 ...
- .net core 反射的介绍与使用
1. 概述反射 通过反射可以提供类型信息,从而使得我们开发人员在运行时能够利用这些信息构造和使用对象. 反射机制允许程序在执行过程中动态地添加各种功能. 2. Type类的介绍 是BCL(基 ...
随机推荐
- input输入框自动填充的问题
火狐浏览器打开页面,input可以自动填充历史输入值,现在想无论input类型是type='text'还是'password'都禁止自动填充,因为我写的页面在input='text'时先检查是否有输入 ...
- linux创建磁盘阵例10
Linux创建RAID10 生产环境中用到的服务器一般都配备RAID阵列卡,尽管服务器的价格越来越便宜,但是我们没有必要为了做一个实验而去单独购买一台服务器,而是可以学会使用mdadm命令在Linux ...
- Halo 开源项目学习(四):发布文章与页面
基本介绍 博客最基本的功能就是让作者能够自由发布自己的文章,分享自己观点,记录学习的过程.Halo 为用户提供了发布文章和展示自定义页面的功能,下面我们分析一下这些功能的实现过程. 管理员发布文章 H ...
- WPF行为基础
理解行为 复杂的UI效果(缩放.拖拽.平滑等)通过样式与触发器比较难以实现,通过引入行为模型来实现.使用行为也可以处理UI操作之外的业务 程序集引用 System.Windows.Interactiv ...
- 1903021121—刘明伟—Java第三周作业—学习在eclipse上创建并运行java程序
项目 内容 课程班级博客链接 19信计班(本) 作业要求链接 第三周作业 作业要求 每道题要有题目,代码,截图 扩展阅读 eclipse如何创建java程序 java语言基础(上) 扩展阅读心得: 想 ...
- 【算法】冒泡排序(Bubble Sort)(一)
冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是 ...
- unity---UI管理模块
UI管理器 任务: 1.所有面板的父类,2.UIMgr 所有UI控件都继承UIBehaviour 面板基类 找到相应空间 简化后 也存在问题:一个物体可以同时挂载两个组件 导致键相同,而值不同, 将值 ...
- 深入C++02:深入学习C++还必须掌握的基础
深入学习C++还必须掌握的基础 掌握形参带默认的函数 1.给默认值方向:从右向左给默认值: 2.调用效率:如果传默认值或者立即数(不需要从容器或内存取取的数字)的话都是直接将数字直接push进栈:没有 ...
- MySQL之事务和redo日志
事务 事务的四个ACID特性. Atomicity 原子性 Consistency 一致性 Isolation 隔离性 Durability 持久性 原子性 原子性即这个事务的任务要么全做了,要么全部 ...
- redis客户端打不开 提示cannot connect to server dev.check log for details
我当前状况是redis客户端打不开,之前一直好好的(虽然作为一个程序员我不配说这句话,哈哈),但是我排查了我觉得所有的可能性,我用的阿里云的redis(还没有到购买到期时间),然后我就关闭了防火墙,你 ...