如何在AssemblyResolve事件之前在运行时加载程序集?

11

我试图在我的解决方案中实现某种“静态链接”程序集,所以我尝试了以下操作:

  • 将引用我的程序集添加到解决方案中,并设置CopyLocal = false
  • 使用“作为链接添加”将.dll文件本身添加到我的解决方案中
  • 使用“添加资源” - “添加现有文件”将.dll文件本身添加到我的资源中
  • 将我的程序集中的某些类型作为private MyObject temp = new MyObject();添加到Form1中

经过这些步骤后,我得到了预期的FileNotFoundException。因此,让我们尝试使用快速技巧在AssemblyResolveEvent中加载程序集。

AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
    {
        Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
        return MyAssembly;
    };
所以这个方法能够工作!我能够从资源文件中加载我的程序集,并在AssemblyResolveEvent中使用它。但是,如果在其他任何地方找不到我的程序集,才会触发此事件。但是我该如何让我的程序集在.Net尝试搜索其他地方之前被加载呢?
由于来自检查先前引用的程序集的事实,我认为预先将程序集加载到域中是可能的,并且这将被采用。
我尝试在 program.cs 中使用以下 Main() 方法实现此目的。
static void Main()
{
    LoadMyAssemblies();
    AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => LoadMyAssemblies();
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

private static Assembly LoadMyAssemblies()
{
    Assembly result = AppDomain.CurrentDomain.Load(Properties.Resources.MyStaticAssembly);
    return result;
}

但是它仍然遇到了 ResolveEventHandler。并且更加好的是,如果我重新加载程序集并查看 AppDomain.CurrentDomain.GetAssemblies(),我可以看到我的程序集被加载了两次!!

那么有什么想法,为什么在 AssemblyResolve 事件之前加载它时,我的已加载程序集不会被考虑?通过调试器的帮助,当从 AssemblyResolve 调用返回 null 时,我也返回了 null,但在这种情况下,我得到了 FileNotFoundException。

2个回答

3

如果你不知道,微软研究院有一个叫做ILMerge的工具,可以将程序集合并成一个文件。

此外,你还可以使用Assembly Linker tool创建多文件程序集。

另外回答你最初的问题,我认为问题在于运行时不知道你手动加载的程序集是它要寻找的程序集。因此,在程序集解析事件中,不要再次加载程序集,只需返回你手动加载的程序集的引用即可。


ILMerge可能已经在其他情况下使用,但对于这种情况它不是最好的解决方案。在AssemblyResolve中返回相同的程序集也不是一个好的解决方案,因为如果相同的程序集也位于程序文件夹或GAC中,则会使用该程序集而不会引发事件。 - Oliver

3
CLR绑定器不知道LoadMyAssemblies()与AssemblyResolve事件执行相同的操作,它们都试图查找并加载相同的程序集。
当绑定器决定已经搜索了所有可能(对于该应用程序是可搜索的)的位置并且无法找到匹配项时,始终会触发AssemblyResolve事件。
这引出了最初的问题,为什么要静态链接托管程序集?阅读此帖子,可以获得大量有关此内容的讨论Static linking advantages 我将回答如何避免触发AssemblyResolve事件的部分 1)将程序集放入GAC。就绑定器而言,GAC总是优先。 2)将程序集放置在探测路径中,并确保绑定器捕获它(在MSDN上查找“运行时如何定位程序集”以获取更多信息)。

你是对的,CLR 绑定程序确实不知道我的函数。但正如你已经提到的,在搜索完所有可能的位置后,它将触发 AssemblyResolve 事件。但这并不正确!它只是没有查看当前 AppDomain 中已加载程序集的列表!但在阅读了此文档之后(http://msdn.microsoft.com/en-us/library/aa98tba8.aspx),它应该会查找那里。 - Oliver

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