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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1159192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:37:36  来源:igfitidea点击:

Howto load assemby at runtime before AssemblyResolve event?

c#.net-3.5assemblies

提问by Oliver

Actually i tried to implement some kind of 'statically linked' assemblies, within my solution. So i tried the following:

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

  • Adding a reference to my assembly with CopyLocal = false
  • Adding the .dll file itself to my solution with 'Add as link'
  • Adding the .dll file itself to my resources with 'Add Resource' - 'Add Existing File'
  • Adding some type out of my assembly into Form1 as private MyObject temp = new MyObject();
  • 使用 CopyLocal = false 添加对我的程序集的引用
  • 使用“添加为链接”将 .dll 文件本身添加到我的解决方案中
  • 使用“添加资源”-“添加现有文件”将 .dll 文件本身添加到我的资源中
  • 将我的程序集中的某种类型添加到 Form1 中 private MyObject temp = new MyObject();

After these steps i got the FileNotFoundException as expected. So let's try to load the assembly within the AssemblyResolveEvent with this quick hack

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

AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
    {
        Assembly MyAssembly = AppDomain.CurrentDomain.Load(Properties.Resources.ExternalAssembly);
        return MyAssembly;
    };

So this works! I'm able to load my assembly from a resource file within a AssemblyResolveEvent. But this event only happens, if it couldn't find my assembly anywhere else. But how can i get my assembly be loaded before.Net tries to search the different places??

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

Due to the facts from Checking for Previously Referenced Assembliesi thought it would be possible to load the assembly beforehand into the domain and this would be taken.

由于检查以前引用的程序集的事实,我认为可以预先将程序集加载到域中,这将被采用。

I tried this within program.cs by using the following Main() method

我在 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;
}

But it still runs into the ResolveEventHandler. And far more better, if i load the assembly again and take a look into AppDomain.CurrentDomain.GetAssemblies()i can see that my assembly is loaded twice!!

但它仍然运行到 ResolveEventHandler 中。更好的是,如果我再次加载程序集并查看AppDomain.CurrentDomain.GetAssemblies()我可以看到我的程序集加载了两次!

So any idea why my loaded assembly won't be taken into account when it is loaded before the AssemblyResolve event?? With help of the debugger i also returned a null when the call came from AssemblyResolve, but in this case i got a FileNotFoundException as at the beginning.

那么知道为什么我加载的程序集在 AssemblyResolve 事件之前加载时不会被考虑在内吗?在调试器的帮助下,当调用来自 AssemblyResolve 时,我也返回了一个空值,但在这种情况下,我在开始时得到了 FileNotFoundException。

回答by Sijin

Just in case you didn't know, there is a tool called ILMergefrom MS Research that merges assemblies into one file.

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

Also you can create Multi-file assemblies using the Assembly Linker tool.

您也可以使用程序集链接器工具创建多文件程序集。

Plus to answer you original question, the problem I think is that the runtime does not know that the assembly you loaded manually is the one it should be looking for. So in the assembly resolve event instead of loading the assembly again, just pass back the reference to the assembly that you've manually loaded.

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

回答by Sijin

The CLR Binder doesn't know that LoadMyAssemblies() does the same thing as the AssemblyResolve event, and that they are both trying to look for the same assembly and load it.

CLR Binder 不知道 LoadMyAssemblies() 与 AssemblyResolve 事件执行相同的操作,并且它们都在尝试查找相同的程序集并加载它。

AssemblyResolve event always gets fired at the point at which the Binder decides that it has searched all possible locations (that are searchable wrt that application) and could not find a match.

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

This begs the original question, which is, why would you want to statically link your managed assemblies? Read this thread for a lot of discussion on this Static linking advantages

这引出了最初的问题,即为什么要静态链接托管程序集?阅读此线程以了解有关此静态链接优势的大量讨论

I'll go ahead and answer the part on how to avoid hitting the AssemblyResolve event 1) Put the assembly into the GAC. As far as the Binder is concerned, the GAC always wins. 2) Place your assembly in the probing path and make sure that the Binder picks it up (look for the article 'How the runtime locates assemblies' on MSDN for more on this).

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