ChatGPT解决这个技术问题 Extra ChatGPT

LoadFile 和 LoadFrom 与 .NET 程序集的区别?

我正在查看 msdn 文档,但我仍然对加载程序集时使用 LoadFileLoadFrom 之间的确切区别感到有些困惑。有人可以提供一个例子或类比来更好地描述它。 MSDN 文档让我更加困惑。此外,ReflectionOnlyLoadFromLoadFrom 相同,只是它仅在反射模式下加载程序集。

由于我的 .NET 经验不是最好的,这里有一些关于使用 LoadFile 的 MSDN 文档的问题:

1) LoadFile 检查具有相同标识但位于不同路径的程序集是什么意思?身份是什么(例子)?

2) 它指出 LoadFile 不会将文件加载到“LoadFrom Context”中,并且不会使用加载路径解析依赖关系。这是什么意思,有人可以举个例子吗?

3) 最后,它指出 LoadFile 在这种有限的场景中很有用,因为 LoadFrom 无法加载具有相同身份但不同路径的程序集;它只会加载第一个这样的程序集,这又让我想到了同样的问题,程序集的身份是什么?

说真的,我有时也认为 MS 应该聘请更好的作家或其他人,因为这些句子并不总是可以理解的......
另请参阅undocumentation
@ColonelPanic MS 可以说一切都记录在案......但有一个零帮助因素。

L
Lukas

这清楚了吗?

// 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 的许多理由,但如果您需要在同一程序集的不同副本上使用反射,它就在那里。


CodeBase 和 Identity 一样吗?
不,我只是在这里使用 CodeBase 作为程序集的任意属性来说明第二个程序集实例指向“错误”文件(在第一个示例中)。我正在用更多细节更新我的答案。
它清除了一点,但是当使用 LoadFrom 和使用 LoadFile 时,path1 和 path2 如何指向磁盘上同一程序集的不同副本,path1 和 path2 指向不同的程序集。什么是 path1 和 path2 的示例?谢谢你的耐心。
为什么用 string.Compare(x, y) == 0 检查两个字符串引用的值是否相等?我想你想要x == y在那里?如果出于晦涩的原因您确实需要依赖于文化的相等性检查,例如,写 string.Equals(x, y, StringComparison.CurrentCulture) 会更清楚。
@JeffSternal 关于“Suzanne Cook 大会身份”的链接似乎在这里被破坏了......
m
mdonoughe

Suzanne Cook's blog

LoadFile 与 LoadFrom 小心——它们不是一回事。 LoadFrom() 通过 Fusion,如果已经在 LoadFrom 上下文中加载了一个程序集,则可以将其重定向到不同路径但具有相同标识的另一个程序集。 LoadFile() 根本不通过 Fusion 绑定 - 加载器只是继续并准确地加载*调用者请求的内容。它不使用 Load 或 LoadFrom 上下文。所以, LoadFrom() 通常会给你你所要求的,但不一定。 LoadFile() 适用于那些真正、真正想要确切要求的人。 (*然而,从 v2 开始,策略将同时应用于 LoadFrom() 和 LoadFile(),因此 LoadFile() 不一定是请求的内容。此外,从 v2 开始,如果具有其标识的程序集位于GAC,将使用 GAC 副本。使用 ReflectionOnlyLoadFrom() 准确加载您想要的内容 - 但请注意,以这种方式加载的程序集无法执行。) LoadFile() 有一个问题。由于它不使用绑定上下文,因此不会在其目录中自动找到其依赖项。如果它们在 Load 上下文中不可用,则必须订阅 AssemblyResolve 事件才能绑定到它们。

请参阅here

另请参阅同一博客上的 Choosing a Binding Context 篇文章。


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

经过一番摸索,今天下午我自己发现了一个不同之处。

我想在运行时加载一个 DLL,而 DLL 位于另一个目录中。该 DLL 有自己的依赖项 (DLL),它们也位于同一目录中。

LoadFile():加载特定的 DLL,但不加载依赖项。因此,当第一次从 DLL 中调用其他 DLL 时,它会抛出 FileNotFoundException。

LoadFrom():加载我指定的 DLL 以及该目录中的所有依赖项。


那正是我的问题!在我刚刚加载 .LoadFile 的程序集所引用的程序集中创建一个对象的新实例时,我得到了 FileNotFoundException。将此更改为 .LoadFrom 似乎可以解决问题,但我不知道为什么!谢谢
谢谢,我也遇到了同样的问题。
但是 LoadFromLoadFile 是不同的。所以你不能只替换这两个
@zoli 是正确的,我的帖子解释了差异以及为什么它们不可互换
G
Gregg DeMasters

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


P
Pang

.NET 有不同的加载上下文。苏珊娜库克在这里写了关于他们的文章:https://docs.microsoft.com/en-us/archive/blogs/suzcook/choosing-a-binding-context

这是 .NET 隔离不混淆引用的方式。


L
Lalit

我注意到的一个区别是:

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

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


这是不正确的。是什么让您相信 Assembly.LoadFile 将程序集加载到另一个 AppDomain 中?
D
David Roth

在我的例子中,我只需要简单地删除位于@C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files 的 ASP 应用程序缓存。它在站点首次运行时重建。请务必先停止 IIS。

希望这对像我这样的人有所帮助。