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

时间:2009-07-21 13:31:33

标签: c# .net-3.5 assemblies

实际上我试图在我的解决方案中实现某种“静态链接”程序集。所以我尝试了以下内容:

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

在这些步骤之后,我按预期得到了FileNotFoundException。因此,让我们尝试使用这个快速入侵

在AssemblyResolveEvent中加载程序集
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
    {
        Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
        return MyAssembly;
    };

所以这个有效!我可以从AssemblyResolveEvent中的资源文件加载我的程序集。但是这个事件只会发生,如果它无法在其他任何地方找到我的组件。但是如何在之前加载我的程序集.Net尝试搜索不同的地方?

由于来自Checking for Previously Referenced Assemblies的事实,我认为可以预先将程序集加载到域中,这将被采用。

我在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,但是在这种情况下,我在开头就得到了一个FileNotFoundException。

2 个答案:

答案 0 :(得分:3)

万一你不知道,MS Research有一个名为ILMerge的工具,它将程序集合并到一个文件中。

您还可以使用Assembly Linker tool创建多文件程序集。

另外回答你原来的问题,我认为问题是运行时不知道你手动加载的程序集应该是它应该寻找的程序集。因此,在程序集解析事件中,而不是再次加载程序集,只需将引用传递回您手动加载的程序集。

答案 1 :(得分:3)

CLR Binder不知道LoadMyAssemblies()与AssemblyResolve事件做同样的事情,并且他们都试图寻找相同的程序集并加载它。

AssemblyResolve事件总是在Binder决定搜索所有可能的位置(可以搜索该应用程序)并且找不到匹配的位置被触发。

这引出了原始问题,也就是说,为什么要静态链接托管程序集?阅读此主题以获取有关此Static linking advantages

的大量讨论

我将继续回答关于如何避免遇到AssemblyResolve事件的部分 1)将组件放入GAC。就Binder而言,GAC总是获胜。 2)将程序集放在探测路径中,并确保Binder选择它(在MSDN上查找文章“运行时如何定位程序集”以获取更多信息)。