C#反射之Assembly.Load,Assembly.LoadFile 与 Assembly.LoadFrom方法介绍

一些关于C#反射的知识,估计也就最多达到使用API的程度,至于要深入了解,以现在的水平估计很难做到,所以下面此篇文章,以作为一个阶段的总结。

对于反射的总结,我想从以下几个方面展开,首先是反射程序集,模块,类的成员以及成员的一些信息;接下来就是动态调用类的成员方法;第三个方面就动态产生程序集,模块和类以及类的成员。好了,现在就让我们从反射各种信息开始吧

在C#中,我们要使用反射,首先要搞清楚以下命名空间中几个类的关系:

System.Reflection命名空间

(1)   AppDomain:应用程序域,可以将其理解为一组程序集的逻辑容器

(2)   Assembly:程序集类

(3)   Module:模块类

(4)   Type:使用反射得到类型信息的最核心的类

他们之间是一种从属关系,也就是说,一个AppDomain可以包含N个Assembly,一个Assembly可以包含N个Module,而一个Module可以包含N个Type.

AppDomain这个类我们等下再来讲解。我们先关注Assembly个类

在程序中,如果我们要动态加载一个程序集怎么办呢?有几种方式可以使用,分别是Load、LoadFrom和LoadWithPartialName三个Assembly的静态方法.

先来讲解Assembly.Load方法,该方法会有多个重载版本,其中一个就是提供程序集的详细信息,即程序集的标识,包括程序集的名称,版本,区域信息,公有密钥标记,全部都是以一个字符串的形式提供,例如:"MyAssembly,Version=1.0.0.0,culture=zh-CN,PublicKeyToken=47887f89771bc57f”.

那么,使用Assembly.Load加载程序集的顺序是怎样的呢?首先它会去全局程序集缓存查找,然后到应用程序的根目录查找,最后会到应用程序的私有路径查找。

当然,如果你使用的是弱命名程序集,也即只给出程序集的名称,那么这个时候,CLR将不会在程序集上应用任何安全或者部署策略,而且Load也不会到全局缓存程序集中查找程序集。

测试加载弱命名程序集的例子如下:

(1)   新建一个控制台应用程序的工程,同时勾选创建解决方案

(2)   在解决方案中新建一个类库的项目,随便写一个类和一个方法

(3)   在控制台项目中,首先不添加引用,直接在Main方法中添加如下代码:

Assembly assembly = Assembly.Load("MyAssembly");

if (assembly != null)

{ Console.WriteLine("加载成功"); }

执行程序,会抛出异常,说找不到该程序集。什么原因呢?因为我们使用的是弱命名程序集,Load方法不会去全局程序集缓存中查找,而该应用程序目录下又没有该程序集,所以程序找不到。这个时候,我们把程序稍微改一下,不用添加代码,只需添加对MyAssembly的引用,重新运行程序,加载成功了。

接下来,我们就要看看Load怎么加载强命名程序集了,这个步骤稍微有些复杂。还是刚才的项目,找到MyAssembly.dll程序集所在的目录,一般在bin"Debug目录下

(1)生成密钥对文件   sn –k MyAssemblyKey.keys

你也可以自己随便起一个密钥对文件名

(2)生成公钥文件

sn –p MyAssemblyKey.keys MyAssemblyPublicKey.PublicKey

注:查看公钥命令:sn –tp MyAssemblyPublicKey.PublicKey

(3)创建强命名程序集。

很简单,只需要在声明命名空间的那句代码上加上如下特性:

[assembly:AssemblyKeyFileAttribute(@”D:"Test"MyAssemblyKey.keys”)]

(4)   编译项目

(5)   将程序集添加到程序集全局缓存

gacutil –i MyAssembly.dll

这个时候,转到加载程序集的项目中,将Load方法中的参数改为”程序集名,Version=版本,culture=区域信息,PublicKeyToken=公钥“,然后再去掉对程序集的引用,我们会发现,程序运行成功。表明Load到全局缓存区查找到了该程序集。

使用Load方法加载程序集,特别是强命名程序集,能在程序集上应用安全和部署策略,推荐使用该方法动态加载程序集,至于LoadFrom和LoadWithPartialName。

首先我们还是来看看LoadFrom方法,这个方法的原理是这样的:我们如果要使用它来动态加载程序集,必须告诉它程序集的路径,也即在哪个目录下面,CLR会去加载与你指定的路径完全匹配的程序集。记住,当我们指定程序集路径时,不能包括任何关于程序集强命名的信息,所以,CLR不会在我们指定的程序集文件上应用任何策略,而且也不会去任何其他的地方搜索程序集,简言之,它就是指哪打哪,呵呵。

例如:你有个程序集在D:/Test/MyAssembly.dll,你要用Assembly.LoadFrom加载该程序集,代码就如下:

Assembly assembly = Assembly.LoadFrom(@”D:/Test/MyAssembly.dll”);

对于,LoadWithParitalName方法,推荐大家最好不要使用它,因为程序无法确定最终要去加载哪个程序集的版本,所以我们这里只是简单的介绍一下它的工作原理:你可以传递一个程序集标识给它,包括程序集名称,至于其他信息是可选的(区域信息,公有密钥等),该方法执行时,会首先检查应用程序中配置文件的qualifyAssembly节点,如果存在,则把该部分名称的程序集替换成完全的程序集标识,如果不存在,则使用程序集名称先到应用程序根目录下查找,然后是私有目录,没有找到的话,就到程序集全局缓存中查找。简单过程如下:

应用程序根目录 -> 应用程序私有目录 -> 程序集全局缓存.

Assembly.Load()方法,Assembly.LoadFrom()方法,Assembly.LoadFile()方法的区别!

1,Assembly.Load()

这个方法通过程序集的长名称(包括程序集名,版本信息,语言文化,公钥标记)来加载程序集的,会加载此程序集引用的其他程序集,一般情况下都应该优先使用 这个方法,他的执行效率比LoadFrom要高很多,而且不会造成重复加载的问题(原因在第2点上说明)

使用这个方法的时候, CLR会应用一定的策略来查找程序集,实际上CLR按如下的顺序来定位程序集:

⑴如果程序集有强名称,在首先在全局程序集缓(GAC)中查找程序集。

⑵如果程序集的强名称没有正确指定或GAC中找不到,那么通过配置文件中的<codebase>元素指定的URL来查找

⑶如果没有指定强名称或是在GAC中找不到,CLR会探测特定的文件夹:

假设你的应用程序目录是C:/AppDir,<probing>元素中的privatePath指定了一个路径Path1,你要定位的程序集是AssemblyName.dll则CLR将按照如下顺序定位程序集

C:/AppDir/AssemblyName.dll

C:/AppDir/AssemblyName/AssemblyName.dll

C:/AppDir/Path1/AssemblyName.dll

C:/AppDir/Path1/AssemblyName/AssemblyName.dll

如果以上方法不能找到程序集,会发生编译错误,如果是动态加载程序集,会在运行时抛出异常!

2,Assembly.LoadFrom()

这个方法从指定的路径来加载程序集,实际上这个方法被调用的时候,CLR会打开这个文件,获取其中的程序集版本,语言文化,公钥标记等信息,把他们传递给 Load方法,接着,Load方法采用上面的策略来查找程序集。如果找到了程序集,会和LoadFrom方法中指定的路径做比较,如果路径相同,该程序集 会被认为是应用程序的一部分,如果路径不同或Load方法没有找到程序集,那该程序集只是被作为一个“数据文件”来加载,不会被认为是应用程序的一部分。 这就是在第1点中提到的Load方法比LoadFrom方法的执行效率高的原因。另外,由于可能把程序集作为“数据文件”来加载,所以使用 LoadFrom从不同路径加载相同程序集的时候会导致重复加载。当然这个方法会加载此程序集引用的其他程序集。

3,Assembly.LoadFile()

这个方法是从指定的文件来加载程序集,和上面方法的不同之处是这个方法不会加载此程序集引用的其他程序集!

结论:一般大家应该优先选择Load方法来加载程序集,如果遇到需要使用LoadFrom方法的时候,最好改变设计而用Load方法来代替!

另:Assembly.LoadFile 与 Assembly.LoadFrom的区别

1、Assembly.LoadFile只载入相应的dll文件,比如Assembly.LoadFile("abc.dll"),则载入abc.dll,假如abc.dll中引用了def.dll的话,def.dll并不会被载入。

Assembly.LoadFrom则不一样,它会载入dll文件及其引用的其他dll,比如上面的例子,def.dll也会被载入。

2、用Assembly.LoadFrom载入一个Assembly时,会先检查前面是否已经载入过相同名字的Assembly,比如abc.dll有两个版本(版本1在目录1下,版本2放在目录2下),程序一开始时载入了版本1,当使用Assembly.LoadFrom("2//abc.dll")载入版本2时,不能载入,而是返回版本1。Assembly.LoadFile的话则不会做这样的检查,比如上面的例子换成Assembly.LoadFile的话,则能正确载入版本2。

LoadFile:加载指定路径上的程序集文件的内容。LoadFrom: 根据程序集的文件名加载程序集文件的内容。

区别:

LoadFile 方法用来来加载和检查具有相同标识但位于不同路径中的程序集.但不会加载程序的依赖项。

LoadFrom 不能用于加载标识相同但路径不同的程序集。

【转载】http://blog.csdn.net/guxiaoshi/article/details/5009604

时间: 2024-10-17 16:10:40

C#反射之Assembly.Load,Assembly.LoadFile 与 Assembly.LoadFrom方法介绍的相关文章

工厂模式的Assembly.Load(path).CreateInstance(className)出错解决方法

1.问题描述 ★代码展示 下面是Factory中的一段代码: '********************************************** ' 文 件 名:DataAcess ' 命名空间:Factory ' 内 容: ' 功 能:创建用户需要的接口 ' 文件关系: ' 作 者:令仔很忙 ' 小 组: ' 生成日期:2014-07-28 17:37:52 ' 版 本 号:V2.0 ' 修改日志: ' 版权说明: '********************************

C#反射-Assembly.Load、LoadFrom与LoadFile进阶

关于.NET中的反射,常用的有三个方法: Assembly.Load()Assembly.LoadFrom()Assembly.LoadFile() 下面说说这三个方法的区别和一些细节问题 1. Assembly.Load() 简介 Load()方法接收一个String或AssemblyName类型作为参数,这个参数实际上是需要加载的程序集的强名称(名称,版本,语言,公钥标记).例如.NET 2.0中的FileIOPermission类,它的强名称是: System.Security.Permi

Assembly.Load()方法,Assembly.LoadFrom()方法,Assembly.LoadFile()方法的区别!

参考: http://www.cnblogs.com/benwu/archive/2009/10/24/1589096.html http://www.cnblogs.com/xuefeng1982/archive/2009/11/09/1598956.html 今天总算弄明白了Assembly.LoadFrom 与Assembly.Load 与 Assembly.LoadFile的一些区别, 以前只是用Assembly.Load来生成实例,现在遇到一个问题,就是从应用程序中来创建窗体, 网上找

关于反射Assembly.Load(&quot;程序集&quot;).CreateInstance(&quot;命名空间.类&quot;)

关于反射Assembly.Load("程序集").CreateInstance("命名空间.类") 而不管在哪一层写这段代码其中的("程序集")读取的实际是web层bin文件夹下的dll,也就是说你反射的类的程序集dll在web层的bin下必须有 Assembly.Load("程序集名") Assembly.LoadFrom("程序集实际路径") 说到加载程序集,有两种方法Assembly.LoadFrom

Assembly.Load(path).CreateInstance 反射出错解决办法

最近采用工厂模式反射DAL层出现一些问题,所以自己想写一下自己认为标准解决的思路和解决方法以备后用. 1.这是项目结构 2.这是DALFactory 反射代码 #region 创建对象(不使用缓存) /// <summary> /// 创建对象(不使用缓存) /// </summary> /// <param name="AssemblyPath"></param> /// <param name="ClassNamesp

Assembly.Load未能加载文件或程序集“”或它的某一个依赖项。系统找不到指定的文件

项目采用了三层架构和工厂模式,并借鉴了PetShop的架构,因为这个项目也是采用分布式的数据库,目前只有三个数据库,主要出于提高访问性能考虑. 原来是按照网上对PetShop的介绍来给各项目添加引用的. 1.Web 引用 BLL.2.BLL 引用 IDAL,Model,使用DALFactory创建实例.3.IDAL 引用 Model. 在编程中,使用反射(IoC)是一个很好的架构.在.Net中,System.Reflection命名空间提供了对反射的支持.然而,很多朋友在使用Assembly.L

Assembly.Load()出错

在研究一段关于反射的代码时,Assembly.Load(程序集名称)总是报错,未找到文件, 出错原因目前发现两个: 1.程序集名称不对,后面的命名空间也有可能不对,需要从属性里查看并按需修改: 2.在使用反射时,由于加载的项目比较多,未对生成的dll进行统一管理和存放,导致U层下的bin/debug下没有相应的dll文件,此时需要修改dll生成路径或者将相应的dll拷入U层bin/debug路径下

ASP.NET MV3 部署网站 报&quot;Could not load file or assembly &#39; System.Web.Helpers “ 错的解决方法

转自:http://www.cnblogs.com/taven/archive/2011/08/14/2138077.html 国内很多网站空间都只支持.NET 2.0 和 .NET 3.0 3.5,很少有空间商支持.NET 4的,即使有个别支持.NET 4,但是不支持MVC的默认路由访问形式. Go Daddy 的主机支持,并且费用很低,系统为 Win 2008 R2 64位,10GB网站空间,网站并发最便宜的也支持100个,PHP支持5.2和5.3,.NET支持 ASP.NET v1.0/2

xmlns:sys=&quot;clr-namespace:System;assembly=mscorlib&quot; NOTE: System;与assembly中间不能有空格

xmlns:sys="clr-namespace:System;assembly=mscorlib"  NOTE: System;与assembly中间不能有空格 否则报错, Error 1 The URI "clr-namespace:System; assembly=mscorlib" is not a valid namespace identifier. D:\Personal\WPF\WpfApplication1\WpfApplication1\Main