一:Assembly.Load()
Assembly.Load可以从内存、文件中加载程序集,主要的重载方法有:
Load(Byte[]):加载带有基于通用对象文件格式 (COFF) 的映像的程序集,该映像包含已发出的程序集。 此程序集将会加载到调用方的应用程序域中。
Load(string):用指定的名称加载程序集,比如Assembly.Load("PoemGame.Eventhandlers"),这里的名称不是文件名,是程序集的长格式或短格式。
Load(AssemblyName):使用程序集的名称加载程序集。
CLR内部普遍使用了Load()方法来加载程序集,在Load()方法的内部,CLR首先会应用这个程序集的版本绑定重定向策略,接着在GAC中查找目标程序集。如果GAC中没有找到,则会在应用程序目录和子目录中寻找(应用配置文件的codebase所指定的位置) |
如果希望加载弱命名程序集,Load()方法就不会去GAC中查找 |
当Load()找到目标程序集时,就会加载它,并返回一个相应Assembly对象的引用 |
当没有找到程序集时,会抛出System.IO.FileNotFoundException异常。 |
当存在特定CPU架构的程序集时,CLR会优先加载当前架构的程序集(例如x86版本优先于IL中立版本) |
如果希望强迫加载某个架构版本的程序集,需要在强名称中加以指定。ProcessorArchitecture可以为x86 IA64 AMD64或MSIL,当然还有None |
Load方法与Win32函数中的LoadLibrary方法等价 |
二:Assembly.LoadFrom()
LoadFrom()方法可以从指定文件中加载程序集,通过查找程序集的AssemblyRef元数据表,得知所有引用和需要的程序集,然后在内部调用Load()方法进行加载。例如:Assembly.LoadFrom(@"C:\ABC\Test.dll");
LoadFrom()首先会打开程序集文件,通过GetAssemblyName方法得到程序集名称,然后关闭文件,最后将得到的AssemblyName对象传入Load()方法中 |
随后,Load()方法会再次打开这个文件进行加载。所以,LoadFrom()加载一个程序集时,会多次打开文件,造成了效率低下的现象(与Load相比) |
由于内部调用了Load(),所以LoadFrom()方法还是会应用版本绑定重定向策略,也会在GAC和各个指定位置中进行查找 |
LoadFrom()会直接返回Load()的结果——一个Assembly对象的引用 |
如果目标程序集已经加载过,LoadFrom()不会重新进行加载 |
LoadFrom支持从一个URL加载程序集(如"http://www.abc.com/test.dll"),这个程序集会被下载到用户缓存文件夹中 |
从URL加载程序集时,如果计算机未联网,LoadFrom会抛出一个异常。如果IE被设置为“脱机工作”,则不会抛出异常,转而从缓存中寻找已下载的文件 |
三:Assembly.LoadFile ()
LoadFile()从一个指定文件中加载程序集,它和LoadFrom()的不同之处在于LoadFile()不会加载目标程序集所引用和依赖的其他程序集。您需要自己控制并显示加载所有依赖的程序集
LoadFile()不会解析任何依赖 |
LoadFile()可以多次加载同一程序集 |
显式加载依赖程序集的方法是,注册AppDomain的AssemblyResolve事件 |
四:总结
1:通过LoadFrom,即使多次调用,传入的是不同路径的同名dll,但是返回的都是首次加载的Assembly对象,如列表所说如果目标程序集已经加载过,LoadFrom()不会重新进行加载
2:通过LoadFile加载dll,该dll会被锁定,如果后续有对此dll的操作,会无法执行,考虑替换用Assembly.Load方法加载字节数组,先将dll读取为字节数组,然后读取,以为加载的是内存中的字节数据,而不是直接从文件系统加载,因此不会锁定文件。通过这种方式即使传入的 fileFullName
是来自两个不同版本但同名的 DLL 文件所解析出的字节数组,返回的 Assembly
对象将会是不同的对象,即使它们的名称相同。
byte[] b = File.ReadAllBytes(fileFullName);
Assembly asm = Assembly.Load(b);
return asm;
3:通过LoadFile加载程序集,不会加载此程序集引用的其他程序集,也就是不会加载相关的依赖项,可能会有异常,要手动加载。
五:区别
1,Assembly.Load()
这个方法通过程序集的长名称(包括程序集名,版本信息,语言文化,公钥标记)来加载程序集的,会加载此程序集引用的其他程序集,一般情况下都应该优先使用 这个方法,他的执行效率比LoadFrom要高很多,而且不会造成重复加载的问题
使用这个方法的时候, 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 不能用于加载标识相同但路径不同的程序集。