【C#进阶系列】23 程序集加载和反射
程序集加载
程序集加载,CLR使用System.Reflection.Assembly.Load静态方法,当然这个方法我们自己也可以显式调用。
还有一个Assembly.LoadFrom方法加载指定路径名的程序集,实际上其内部是先通过AssemblyName.GetAssemblyName获取AssemblyName对象,然后调用Assembly.Load方法。
此时load方法会在各个位置(前面03章讲过)查找程序集,如果已经加载了此程序集就返回已加载的程序集,如果没有加载就去加载找到的程序集,如果没有找到,就加载路径所给的那个程序集。(所以很清楚了解到不一定会加载所指定的那个程序集,而可能是另一个。在这里如果每次生成强命名程序集时更新版本号,才会使LoadFrom方法的行为符合预期)
LoadFrom方法允许传递一个Url作为实参,CLR会下载文件,把它安装到用户的下载缓存中,再从那儿加载文件。
ReflectionOnlyLoadFrom函数也可以加载程序集,且禁止程序集中的任何代码执行。
使用反射构建动态可扩展应用程序
既然加载了程序集,那么就应该要有办法去使用程序集中定义的类,这种办法就是反射。
利用System.Reflection命名空间中包含的类型,可以写代码来反射元数据表,为所加载的程序集中所包含的元数据提供对象模型。
反射一些例子:
首先先建立一个用于反射的程序集,代码如下:
namespace HelloWorld
{
public class Man
{
public string _name;
public Man(String name) {
this._name = name;
}
public void ShowName() {
Console.WriteLine(this._name);
}
}
} namespace HelloWorld
{
public class Troy:Man
{
private string _jobName;
public Troy(string name,string jobName):base(name) {
this._jobName = jobName;
}
public void ShowJobName() {
Console.WriteLine(this._jobName);
}
}
}
然后生成了一个叫HelloWorld.dll的文件,然后开始玩反射
//首先加载程序集,获取程序集对象
Assembly myAssembly=Assembly.LoadFrom("D:\\HelloWorld.dll");
//玩程序集中定义的公共类型
foreach (Type type in myAssembly.ExportedTypes) {
//打印类型全名
Console.WriteLine("类型全名:"+type.FullName);
Console.WriteLine(type.FullName + "的基类:" + type.BaseType.FullName);
//判定类型是否为String(当然这是不可能的,因为只有Man和Troy)
if (type == typeof(String)) {
Console.WriteLine("有个String类型");
}
//Type对象是轻量型的类型引用,更全面的信息在TypeInfo对象(获取TypeInfo对象会强迫CLR确保已加载类型的定义程序集,从而对类型进行解析。(代价高昂)),
//如下转换
TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type);
//也可以反着转
Type tmpType = typeInfo.AsType();
//泛型类型的Type
Type openType = typeof(Dictionary<,>);//开放类型
Type closedType= openType.MakeGenericType(typeof(int), type);//闭合类型
//实例化
Object obj= Activator.CreateInstance(closedType);
Console.WriteLine(obj.GetType());
}
反射的性能
反射是相当强大的机制,但是也有其缺点:
- 反射造成编译时无法保证类型安全性,因为它是在运行时才依靠字符串来对类进行实例化等操作。
- 反射的速度很慢,因为是在运行时靠字符串去标识成员,发现它们,使用它们。整个过程中都是用字符串来搜索。
设计支持加载项的应用程序
构建可扩展应用程序时,一般使用接口而不是基类,因为接口允许加载项开发人员选择自己的基类。
为宿主接口类的方法定义参数和返回类时,尝试使用MSCorLib.dll定义的接口和类型。因为CLR只加载一个MSCorLib.dl,所以不会出现类型版本不匹配的情况,且有助于减少应用程序对内存的需求。
反射与类型的成员
System.Reflection.MemberInfo封装了所有类型成员都通用的一组属性。它的一些派生类如MethodInfo则封装了与特定类型成员相关的更多属性。
直接上代码简单易懂:
class Program
{
static void Main(string[] args)
{
Type type = typeof(Troy);
Object obj = Activator.CreateInstance(type);
MethodInfo[] arrMethod= type.GetMethods();
foreach (var methodInfo in arrMethod) {
if (methodInfo.GetParameters().Length == )
{
methodInfo.Invoke(obj, null);
}
}
Console.Read();
} }
public class Troy{
public string name;
public Troy() {
name = "Troy";
}
public void Show() {
Console.WriteLine(name);
}
}
对于FieldInfo(字段)和PropertyInfo(属性)可以用GetValue和SetValue来获取和设置实例的值,
对于MethodInfo(方法)和ConstructorInfo(构造器)则可以用Invoke来调用,
对于EventInfo(事件)可以用AddEventHandler和RemoveHandler来增加事件回调函数和减少回调函数。
上述方法其实很麻烦,如果用dynamic方法那么就会和一般的写程序一样简单了。
【C#进阶系列】23 程序集加载和反射的更多相关文章
- clr via c# 程序集加载和反射(2)
查看,clr via c# 程序集加载和反射(1) 8,发现类型的成员: 字段,构造器,方法,属性,事件,嵌套类型都可以作为类型成员.其包含在抽象类MemberInfo中,封装了所有类型都有的一组属性 ...
- 重温CLR(十七)程序集加载和反射
本章主要讨论在编译时对一个类型一无所知的情况下,如何在运行时发现类型的信息.创建类型的实例以及访问类型的成员.可利用本章讲述的内容创建动态可扩展应用程序. 反射使用的典型场景一般是由一家公司创建宿主应 ...
- clr via c# 程序集加载和反射集(一)
1,程序集加载---弱的程序集可以加载强签名的程序集,但是不可相反.否则引用会报错!(但是,反射是没问题的) //获取当前类的Assembly Assembly.GetEntryAssembly() ...
- 老调重弹:JDBC系列之<驱动加载原理全面解析) ----转
最近在研究Mybatis框架,由于该框架基于JDBC,想要很好地理解和学习Mybatis,必须要对JDBC有较深入的了解.所以便把JDBC 这个东东翻出来,好好总结一番,作为自己的笔记,也是给读者 ...
- RX系列四 | RxAndroid | 加载图片 | 提交表单
RX系列四 | RxAndroid | 加载图片 | 提交表单 说实话,学RxJava就是为了我们在Android中运用的更加顺手一点,也就是RxAndroid,我们还是先一步步来,学会怎么去用的比较 ...
- .NET 的程序集加载上下文
原文:.NET 的程序集加载上下文 我们编写的 .NET 应用程序会使用到各种各样的依赖库.我们都知道 CLR 会在一些路径下帮助我们程序找到依赖,但如果我们需要手动控制程序集加载路径的话,需要了解程 ...
- CLR中的程序集加载
CLR中的程序集加载 本次来讨论一下基于.net平台的CLR中的程序集加载的机制: [注:由于.net已经开源,可利用vs2015查看c#源码的具体实现] 在运行时,JIT编译器利用程序集的TypeR ...
- 【C#】解析C#程序集的加载和反射
目录结构: contents structure [+] 程序集 程序集的加载 发现程序集中的类型 反射对类型成员的常规操作 发现类型的成员 创建类型的实例 绑定句柄减少进程的内存消耗 解析自定义特性 ...
- 【iOS系列】-UIWebView加载网页禁止左右滑动
[iOS系列]-UIWebView加载网页禁止左右滑动 问题: 做项目时候,用UIWebView加载网页的时候,要求是和微信网页中打开的网页的效果一样,也即是只能上下滑动,不能左右滑动,也不能缩放. ...
随机推荐
- Linux 服务器监控
200 ? "200px" : this.width)!important;} --> 标签:iostat/free/top/dstat 概述 文字主要讲述使用linux自带 ...
- 学习Cassandra的开源电子书(中英文版)
学习Cassandra的开源电子书(中英文版)发布啦:http://teddymaef.github.io/learncassandra/ 之前发布了英文版,现在包含中文版了. 学习Cassandra ...
- Eclipse代码格式化规范
附件()是Eclipse代码格式文件,根据以下步骤导入到Eclipse中,帮助规范代码格式. 导入步骤:1. Window -> Performances2. Java -> Code S ...
- 获取bing.com的图片并在gnome3中设置自动切换
发现 bing.com 上的图片很好看,因此打算每天把 bing.com 的图片下载下来,用作桌面. 需要做的是两个部分,爬取图片到目录和设置目录图片为桌面背景并可以自动切换. 第一部分,下载图片,使 ...
- Hibernate框架的配置
概念 持久化框架 把对象保存到数据库中,对数据的CURD操作 配置Hibernate 1.在项目中引入Hibernate的Jar包 在 WebContent/WEB-INF/lib 目录下 导入jar ...
- Apk去掉签名以及重新签名的方法
Android开发中很重要的一部就是用自己的密钥给Apk文件签名,不经过签名的Apk文件一般是无法安装的,就算装了最后也是失败. 网上流传的"勾选允许安装未知来源的应用"其实跟签不 ...
- Linux服务器常用操作
Context 客户端:MacOS Terminal终端 服务器端:Linux v2.6 更新项目 进程 查看:ps -ef | grep * 杀死:kill -9 <pid> 数据库 备 ...
- LINQ系列:LINQ to SQL Take/Skip
1. Take var expr = context.Products .Take(); var expr = (from p in context.Products select p) .Take( ...
- jQuery源码分析系列(39) : 动画队列
data函数在jQuery中只有短短的300行代码,非常不起点 ,剖析源码的时候你会发现jQuery只要在有需要保存数据的地方无时无刻不依赖这个基础设施 动画会调用队列,队列会调用data数据接口还保 ...
- lua解释执行脚本流程
#include "lua.hpp" #include <iostream> using namespace std; #pragma comment(lib, &qu ...