.NET程序集中LoadFile和LoadFrom的区别是什么?

147
我正在查看msdn文档,但仍不太清楚在加载程序集时使用LoadFileLoadFrom之间的确切区别是什么。是否有人能够提供一个例子或比喻来更好地描述它呢?MSDN文档让我更加困惑。此外,ReflectionOnlyLoadFromLoadFrom是否相同,只是它在反射模式下加载程序集。
由于我的.NET经验不是很丰富,在使用LoadFile的MSDN文档中还有一些问题:
1)是什么意思:LoadFile检查具有相同标识但位于不同路径中的程序集?这个标识是什么(例如)?
2)它指出LoadFile不会将文件加载到“LoadFrom上下文”中,并且不使用加载路径解析依赖项。这是什么意思,可以提供一个例子吗?
3)最后,它指出LoadFile在这种有限的场景中非常有用,因为LoadFrom无法加载具有相同标识但不同路径的程序集;它只会加载第一个这样的程序集,这又带来了同样的问题,程序集的标识是什么?

10
有时候我也认为微软应该雇佣更好的作家或其他人,因为有些句子并不易于理解... - Tarik
9
另请参阅 undocumentation - Colonel Panic
3
@ColonelPanic说,微软可能会说一切都有记录……但是帮助因素为零。 - Legends
7个回答

109

这样清楚了吗?

// path1 and path2 point to different copies of the same assembly on disk:

Assembly assembly1 = Assembly.LoadFrom(path1);
Assembly assembly2 = Assembly.LoadFrom(path2);

// These both point to the assembly from path1, so this is true
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

assembly1 = Assembly.LoadFile(path1);
assembly2 = Assembly.LoadFile(path2);

// These point to different assemblies now, so this is false
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

编辑:针对您在修改后的问题中提出的问题,您绝对需要阅读Suzanne Cook on Assembly Identity

有许多规则管理程序集的加载方式,其中一些规则与它们如何解决依赖关系有关 - 如果您的AssemblyA依赖于AssemblyB,则.NET应该在哪里查找AssemblyB?在全局程序集缓存中,在找到AssemblyA的相同目录中,还是在完全不同的地方?此外,如果它找到该程序集的多个副本,应该选择使用哪一个?

LoadFrom有一套规则,而LoadFile有另一套规则。很难想象使用LoadFile的理由有多少,但如果您需要在相同程序集的不同副本上使用反射,那么它适用于您。


2
代码库和身份是否相同? - Xaisoft
不,我只是在这里将CodeBase用作程序集的任意属性,以说明第二个程序集实例指向“错误”的文件(在第一个示例中)。我正在更新我的答案,提供更多细节。 - Jeff Sternal
1
这有点清楚了,但是当使用LoadFrom时,path1和path2如何指向磁盘上同一程序集的不同副本,而使用LoadFile时,path1和path2指向不同的程序集。path1和path2可能是什么样子的例子呢?感谢您的耐心等待。 - Xaisoft

65

来自Suzanne Cook的博客:

LoadFile与LoadFrom的区别

要小心,它们并不相同。

LoadFrom()通过融合(Fusion)进行绑定,如果在LoadFrom上下文中已经加载了相同标识的程序集,则可以重定向到不同路径上的另一个程序集。

LoadFile()根本不会通过融合进行绑定 - 加载器直接加载调用方请求的内容。它既不使用Load上下文,也不使用LoadFrom上下文。

因此,LoadFrom()通常会给您所需的东西,但不一定如此。LoadFile()适用于那些确实希望获取准确所需内容的人。(然而,从v2开始,政策将应用于LoadFrom()和LoadFile(),因此LoadFile()不一定是准确的。此外,从v2开始,如果具有其标识的程序集在GAC中,则将使用GAC副本。使用ReflectionOnlyLoadFrom()加载确切需要的内容,但请注意,以这种方式加载的程序集无法执行。)

LoadFile()有一个问题。由于它不使用绑定上下文,因此它的依赖项不会自动在其目录中找到。如果它们在Load上下文中不可用,您需要订阅AssemblyResolve事件才能绑定到它们。

请参见这里.

另请参见同一博客的选择绑定上下文文章。


谢谢,我会查看博客的。我在我的帖子中更新了一些关于MSDN文档的问题。 - Xaisoft
@Xaisoft - Suzanne Cook的博客再次提供了有关程序集标识的答案。请参见http://blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx。它本质上是一个“程序集显示名称”,类似于:“System,Version = 1.0.3300.0,Culture = neutral,PublicKeyToken = b77a5c561934e089”,因此包括程序集的实际名称,版本号以及其他标识信息(如PublicKeyToken等)。 - CraigTP
1
当她谈到Fusion时,她指的是什么? - Xaisoft
1
确实,Jeff说得很对。请参考此链接:http://www.grimes.demon.co.uk/workshops/fusionWS.htm,了解有关Fusion子系统及其在.NET中加载程序集的技术的详细教程。 - CraigTP
1
只是一个快速的更新,注意上面的URL(grimes.demon.co.uk/workshops/fusionWS.htm)不再有效,现在已移至:http://www.richardgrimes.com/workshops/fusionWS.htm。 - CraigTP
显示剩余2条评论

53

经过长时间的思考,今天下午我自己发现了一个区别。

我想在运行时加载一个DLL文件,而这个DLL文件存放在另一个目录中。该DLL文件有它自己的依赖项(DLL文件),这些依赖项也存放在同一个目录中。

LoadFile():只加载了指定的DLL文件,但没有加载依赖项。因此,当从DLL文件内部第一次调用其中一个其他DLL文件时,会抛出FileNotFoundException异常。

LoadFrom():加载了我指定的DLL文件以及存放在该目录中的所有依赖项。


4
那正是我的问题!我在创建一个由另一个程序集定义的对象实例时,使用.LoadFile来加载刚刚被引用程序集后会出现“FileNotFoundException”的错误。将其改为使用.LoadFrom似乎解决了这个问题,但我不知道原因!谢谢。 - Connell
但是 LoadFromLoadFile 是不同的。因此,您不能只是替换这两个。 - Zoli
@zoli 是正确的,我的帖子解释了它们之间的区别以及为什么它们不能互换。 - LordWilmore

4

注意:如果一个程序集使用8.3路径加载,然后从非8.3路径加载,尽管它们是同一个物理DLL,但它们将被视为不同的程序集。


1

0
在我的情况下,我只需要简单地删除位于 C:\Windows\Microsoft.NET\Framework\[asp版本]\Temporary ASP.NET Files 的ASP应用程序缓存。当网站第一次运行时,它会被重建。请确保先停止IIS。
希望这能像对我一样对其他人有所帮助。

-2

我注意到的一个区别是:

Assembly.LoadFile - 在不同的AppDomain中以有限的用户权限加载程序集(不同的原则)。无法执行序列化/反序列化等操作。

Assembly.LoadFrom- 在相同的AppDomain中以相同的用户权限加载程序集(相同的原则)。


5
这是不正确的。你怎么相信 Assembly.LoadFile 会把程序集加载到另一个 AppDomain 中呢? - Sven Mawby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接