第二十三章 程序集加载和反射

23.1 程序集加载

JIT编译器将方法的IL代码编译成本机代码时,会查看IL代码中引用了哪些类型。在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所有引用的类型。

通过Assembly的Load方法加载程序集。

23.2 使用反射构建动态可扩展应用程序

 类库需要理解类型的定义才能提供丰富的功能,就适合使用反射。

应用程序需要从特定程序集中加载特定类型以执行特定任务时,也要使用反射。 

23.3 反射的性能

 缺点:

反射造成编译时无法保证类型安全性。

反射速度慢。

使用反射调用成员也会影响性能。用反射调用方法时,首先必须将实参打包成数组;在内部,反射必须将这些实参解包到线程栈上。

最好避免利用反射来访问字段或调用方法/属性。因使用:

让类型从编译时已知的基类型派生。

让类型实现编译时已知的接口。

3.1 发现程序集中定义的类型

3.2 类型对象的准确含义

3.3 构建Exception派生类型的层次结构

3.4 构造类型的实例

  获得对Type派生对象的引用之后,就可以构造该类型的实例了。

System.Activator的CreateInstance方法

System.Activator的CreateInstanceFrom方法

System.AppDomain的方法

System.Reflection.ConstructorInfo的Invoke实例方法

23.4 设计支持加载项的应用程序

构建可扩展应用程序时,接口时是中心。可用基类型代替接口,但接口通常是首选,因为它允许加载项开发人员选择他们自己的基类。设计:

  创建“宿主SDK”(Host SDk)程序集,它定义了一个接口,接口的方法作为宿主应用程序与加载项之间的通信机制使用。为接口方法参数和返回类型时,请尝试使用MSCorLib.dll中定义的其他接口或类型。要传递并返回自己的数据类型,也在“宿主SDK”程序集定义。一旦搞定接口定义,就可为这个程序集赋予强名称,然后把它打包并部署到合作伙伴和用户那里。

  加载项开发人员会在加载项程序集中定义自己的类型。这些程序集将引用你的“宿主”程序集中的类型 。

  创建单独的“宿主应用程序”程序集,在其中包含你的应用程序类型。这个程序集显然要引用“宿主SDK”程序集,并使用其中定义的类型。

23.5 使用反射发现类型的成员

 5.1 发现类型的成员

MemberInfo的所有派生类型都通用的属性和方法

成员名称 成员类型 说明
Name 一个string属性 返回成员名称
DeclaringType 一个Type属性 返回声明成员的Type
Module 一个Module属性 返回声明成员的Module
CustomAttributes 该属性返回一个IEnumerable<CustomAtrributeData>

返回一个集合,其中每个元素都标识了应用该成员的一个定制特性的实例。

 

5.2  调用类型的成员

如何调用成员

 成员类型 调用成员而需要调用的方法 
 FiledInfo

调用GetValue获取字段的值

调用SetValue设置字段的值 

 ConstructorInfo 调用Invoke构造类型的实例并调用构造器 
 MethodInfo 调用Invoke来调用类型的方法 
 PropertyInfo

调用GetValue来调用的属性的get访问器方法

调用SetValue来调用属性的set访问器方法 

EventInfo

调用AddEventHandler来调用事件的add访问器方法

调用RemoveEventHanlder来调用事件的remove访问器方法

 

5.3 使用绑定句柄减少进程的内存消耗

许多应用程序都绑定了一组类型(Type对象)或类型呢成员(MemberInfo派生对象),并将这些对象保存在某种形式的集合中。

开发人员可以使用运行时句柄代替对象以减少工作集(占用得内存)。RuntimeTypeHandle.RuntimeFieldHandle和RuntimeMethodHandle三个类型,包含一个字段“IntPtr”,IntPtr字段是一个句柄,引用了AppDomain的Loader堆中的一个类型,字段或方法。

posted @ 2019-03-04 08:38  郭大大大  阅读(210)  评论(0编辑  收藏  举报