反射原理-图文

①、了解反射前需要知道的结构关系。

反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。 

我们在理解C#反射原理之前需要先搞明白几个概念,以及他们之间的关系。

(1)  AppDomain(Application Domain,简称App Domain):应用程序域,可以将其理解为一组程序集的逻辑容器 。
(2)  Assembly:程序集类 。
(3)  Module:模块类  。
(4)  Type:使用反射得到类型信息的最核心的类  。

他们之间是一种从属关系,也就是说,一个AppDomain可以包含N个Assembly,一个Assembly可以包含N个Module,而一个Module可以包含N个Type,再者一个应用程序可以包含多个AppDomain,当程序跑起来后,对应的进程也可以创建多个appdomain,实现隔离,一个appdomain是不允许直接调用同一个进程中另一个appdomain的类型的,不同进程就更不用说啦。
 

程序代码在编译后生成可执行的应用,通过上图我们首先要了解这种可执行应用程序的结构。 

应用程序结构分为应用程序域—程序集—模块—类型—成员几个层次,公共语言运行库(CLR)加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。 

程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。反射通常具有以下用途。 

  (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。 

  (2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 

  (3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。 

  (4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。 

  (5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。

  (6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。 

  (7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。 

  (8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。 
 

②、反射的概念

反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码 

③、和反射相关的命名空间(我们就是通过这几个命名空间访问反射信息)


   System.Reflection.MemberInfo    
    System.Reflection.EventInfo    
    System.Reflection.FieldInfo   
    System.Reflection.MethodBase    
    System.Reflection.ConstructorInfo    
    System.Reflection.MethodInfo    
    System.Reflection.PropertyInfo    
    System.Type    
    System.Reflection.Assembly    

④、单个程序集的反射方法

我们常用的是Load方法:Load 方法带有一个程序集标志并载入它,Load 将引起CLR把策略应用到程序集上,先后在全局程序集缓冲区,应用程序基目录和私有路径下面查找该程序集,如果找不到该程序集系统抛出异常 。

⑤、程序由.cs代码开始运行的流程

C#是一个编译型的语言,程序在运行C#之前,需要将.cs的文件编译成电脑认识的含0和1的文件,即程序集文件(.dll),然后一个程序运行起来以后,有一个APPDomain,在这个APPDomain中放了我们用到的所有的“Assembly”,然后以“Assembly对象”方式加载到内存中运行。

⑥、如何获取程序运行哪些程序集

通过如下代码我们可以直观的看到程序运行时都有哪些程序集。(前提要引用using system.Reflection)

Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();

⑦、.cs代码经过编译后,在内存中运行时的状态

程序集:*.exe,*.dll  ->加载到内存中就是Assembly对象

类:每个class,interface ->加载到内存中就是Type对象

类的成员:方法,字段,属性,事件等 ->加载到内存中也有对应的对象。

⑧、反射动态创建实例

在程序运行时,动态获取Assembly,Type,MethodInfo,PropertyInfo,FieldInfo,EventInfo的信息。之后动态创建类型实例,以及调用类型实例的成员。

⑨、反射的应用:

框架(Spring .net/.net MVC等)

【原理总结】

原理其实很简单,.net所编写的程序集包含两个重要部分:IL(中间语言代码) 和metadata(元数据)。我们编写的代码中不是有很多很多的类吗,类有很多很多的成员,在编译代码的时候,元数据表就根据代码把类的所有信息都记录在了它里面(其实它就是一个数据结构,组织类的信息)。而反射的过程刚好相反,就是通过元数据里记录的关于类的详细信息找到该类的成员,并能使它“复活”(因为元数据里所记录的信息足够详细,以致于可以根据metadata里面记录的信息找到关于该类的IL code并加以利用)。

光的反射:

生活现象:

程序中代码的反射:

上述讲解中的概念解析

①、什么是AppDomain?

应用程序域:(Application Domain,简称App Domain)一组程序集的一个逻辑容器,进程中的一个逻辑分区。命名空间为system,程序集为mscorlib.dll。无法继承此类。

当一个程序集被执行时,系统就会自动为其创建一个AppDomain,每个APPDomain属于某个进程,一个进程内可以有多个APPDomain;每个APPDomain创建时都有个默认名称,该名称就是:程序集的名称.exe。应用程序域是使用CreateDomain方法创建的,AppDomain实例用于加载和执行程序集(Assembly)。当不再使用AppDomain时,可以将其卸载。

AppDomain唯一的作用就是进行隔离。

具体功能:

隔离,一个AppDomain中的代码创建的对象不能由另一个AppDomain中的代码直接访问。达到隔离应用程序的度效果。当然如果要访问别的AppDomain中的内容,可以使用“按引用封送”或问者“按值封送”的语义。    

AppDomain可以卸载,但不能卸载单独的程序集或类型,只能卸载整个应用程序域。从而卸载包含在该AppDomain中的所有程序集。

AppDomain可以单独保护,AppDomain在创建后,会应用一个权限集,它决定了向这个AppDomain中运行的程序集授予的最大权限。从而保护宿主加载的代码不被破坏。

可以单独实施配置,内AppDomain在创建后,会关联一组配置设置。这些设置主要影响CLR在AppDomain中加载程序集的方式。这些设置涉及搜索容路径、版本重定向、卷影复制以及加载器优化。

②、什么是Assembly类?

Assembly是一个包含来程序的名称,版本号,自我描述,文件关联关系和文件位置等信息的一个集合。在.net框架中通过Assembly类来支持,该类位于System.Reflection下,物理位置位于:mscorlib.dll。
Assembly能干什么?
我们可以通过Assembly的信息来获取程序的类,实例等编程需要用到的信息。
 

③、什么是CLR?

CLR(Comman Language Runtime)公共语言运行库,它负责资源管理(内存分配和垃圾收集等),并保证应用和底层操作系统之间必要的分离。CLR和Java虚拟机一样也是一个运行时环境,是一个可由多种编程语言使用的运行环境。CLR的核心功能包括:内存管理、程序集加载、安全性、异常处理和线程同步,可由面向CLR的所有语言使用。

④、什么是元数据?

元数据:元数据是一种二进制信息,用以对存储在公共语言运行库可移植可执行文件 (PE) 文件或存储在内存中的程序进行描述。将您的代码编译为 PE 文件时,便会将元数据插入到该文件的一部分中,而将代码转换为 Microsoft 中间语言 (MSIL) 并将其插入到该文件的另一部分中。在模块或程序集中定义和引用的每个类型和成员都将在元数据中进行说明。当执行代码时,运行库将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。元数据以非特定语言的方式描述在代码中定义的每一类型和成员。

每个元数据表都保留有关程序元素的信息。例如,一个元数据表说明代码中的类,另一个元数据表说明字段等。如果您的代码中有 10 个类,类表将有 10 行,每行一类。元数据表引用其他的表和堆。

参考链接:

https://www.cnblogs.com/w-wfy/p/7668818.html

https://blog.csdn.net/talent_jian/article/details/54837064

https://blog.csdn.net/yuhan61659/article/details/79498938

https://blog.csdn.net/CJB_King/article/details/80521481

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elsa~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值