程序集加载

JIT编译器将方法的IL代码编译成本地代码时,会查看IL代码中引用了哪些类型。在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型。在AssemblyRef元数据表的记录项中,包含了构成程序集强名称的各个部分。JIT编译器所获取所有这些部分——包括名称(无扩展名和路径)、版本、语言文化和公钥标记(public key token)——并把他们连接成一个字符串。然后,JIT编译器尝试将与该标识匹配的一个程序集加载到AppDomain中(如果还没有加载的话)。如果被加载的程序集是弱命名的,那么标识中就只包含程序集的名称(不包含版本、语言文化及公钥标记信息)。

在内部,CLR使用System.Reflection.Assembly类的静态方法load来尝试加载这个程序集。这个方法在.NET Framework SDK文档中是公开,可调用它显式地将一个程序集加载到AppDomain中。这个方法是CLR中的与win32 LoadLibrary函数等价的方法。Assembly的load方法实际有几个重载的版本。以下是最常用的重载版本的原型:

public class Assembly{
	public static Assembly Load(AssemblyName assemblyRef);
	public static Assembly Load(String assemblyString);
	// ... 不常用的重载方法未再此列出
}

在内部,Load导致CLR向程序集应用一个版本绑定重定向策略,并在GAC(全局程序集缓存)中查找程序集。如果没找到,就接着去应用程序的基目录、私有路径子目录和codebase位置查找。如果调用load时传递的是一个弱命名程序集,Load就不会向程序集应用一个版本绑定策略,CLR也不会去GAC中查找程序集。如果load找到指定的程序集,会返回对代表已加载的那个程序集的一个Assembly对象的引用。如果Load没有找到指定程序集,会抛出一个System.IO.FileNotFoundException .

为了以指定路径名的方式加载一个程序集,要调用Assembly的loadFrom方法:

public class Assembly{
	public static Assembly LoadFrom(string path)
}

LoadFrom首先会调用System.Reflection.AssemblyName类的静态方法GetAssemblyName。该方法打开指定的文件,查找AssemblyRef元数据的记录项,提取程序集标识信息,然后以一个System.Reflection.AssemblyName对象的形式返回这些信息(文件同时会关闭)。然后,LoadFrom方法在内部调用Assembly的load方法,将AssemblyName对象传给它。然后,CLR会为应用版本绑定重定向策略,并在各个位置查找匹配的程序集。如果Load找到了匹配的程序集,就会加载它,并返回代表已加载程序集的一个Assembly对象;LoadFrom方法会将返回这个值。如果Load没有找到匹配的程序集,LoadFrom就会加载通过LoadFrom的实参传递的路径中的程序集。当然,如果已加载了一个具有相同标识的程序集,LoadFrom方法会简单地返回已加载程序集的一个Assembly对象。

顺便说一下LoadFrom方法允许传递一个URL作为实参

vs的UI设计人员和其他工具一般用的是Assembly的LoadFile方法,这个方法可从任意路径加载一个程序集,并可将具有相同标识的一个程序集多次加载到一个AppDomain中。在设计器/工具中对应用程序的UI进行了修改,而且用户重新生成了程序集,便有可能发生这种情况。通过LoadFile加载程序集时,CLR不会自动解析任何依赖性问题;你的代码必须向AppDomain的AssemblyResolve事件登记,并让事件回调方法显示加载任何依赖的程序集。

如果你构建的一个工具只是通过反射来分析程序集的元数据,并希望确保程序集中的任何代码都不会执行,那么加载程序集的最佳方式就是使用Assmbly的ReflectionOnlyLoadFrom方法或者使用Assembly的ReflectionOnlyLoad方法。

许多应用程序都由一个要依赖于众多DLL文件的Exe文件构成。部署这个应用程序时刻,所有文件都必须部署,然而,有一个技术允许只部署一个Exe文件。首先标识出Exe要文件依赖的、同时不是作为Microsoft.Net framework本身的一部分发布的所有DLL文件。然后,将这些DLL添加到vs项目中,对于每个添加的dll,显示属性将“生成操作”更改为“嵌入的资源”。这会导致C#编译器将DLL文件嵌入到Exe文件中,以后只需要部署这个Exe文件即可。

在运行时,CLR会找不到依赖的DLL程序集。为了解决这个问题,当应用程序初始化时,向AppDomain的ResolveAssembly事件登记一个回调方法。代码大致如下:

AppDomain.CurrentDomain.AssemblyResolve +=(sender, args) =>{
	string resourceName ="AssemblyLoadingAndReflection."+ new AssemblyName(args.Name).Name +".dll";
	
	using(var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)){
	var assemblyData = new Byte[stream.Length];
	stream.Read(assemblyData,0, assemblyData.Length);

	return Assembly.Load(assemblyData);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值