如何在 C# 中在运行时加载程序集及其所有依赖项以进行反射?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/59220/
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-03 10:17:37  来源:igfitidea点击:

How Do I Load an Assembly and All of its Dependencies at Runtime in C# for Reflection?

提问by J Wynia

I'm writing a utility for myself, partly as an exercise in learning C# Reflection and partly because I actually want the resulting tool for my own use.

我正在为自己编写一个实用程序,部分是作为学习 C# 反射的练习,部分是因为我实际上希望得到的工具供我自己使用。

What I'm after is basically pointing the application at an assembly and choosing a given class from which to select properties that should be included in an exported HTML form as fields. That form will be then used in my ASP.NET MVC app as the beginning of a View.

我所追求的基本上是将应用程序指向一个程序集并选择一个给定的类,从中选择应该作为字段包含在导出的 HTML 表单中的属性。然后,该表单将在我的 ASP.NET MVC 应用程序中用作视图的开头。

As I'm using Subsonic objects for the applications where I want to use, this should be reasonable and I figured that, by wanting to include things like differing output HTML depending on data type, Reflection was the way to get this done.

当我在我想要使用的应用程序中使用 Subsonic 对象时,这应该是合理的,我认为,通过想要根据数据类型包含不同的输出 HTML 之类的东西,反射是完成这项工作的方法。

What I'm looking for, however, seems to be elusive. I'm trying to take the DLL/EXE that's chosen through the OpenFileDialog as the starting point and load it:

然而,我正在寻找的东西似乎难以捉摸。我试图以通过 OpenFileDialog 选择的 DLL/EXE 作为起点并加载它:

String FilePath = Path.GetDirectoryName(FileName);
System.Reflection.Assembly o = System.Reflection.Assembly.LoadFile(FileName);

That works fine, but because Subsonic-generated objects actually are full of object types that are defined in Subsonic.dll, etc., those dependent objects aren't loaded. Enter:

这工作正常,但是因为 Subsonic 生成的对象实际上充满了在 Subsonic.dll 等中定义的对象类型,所以不会加载这些依赖对象。进入:

AssemblyName[] ReferencedAssemblies = o.GetReferencedAssemblies();

That, too, contains exactly what I would expect it to. However, what I'm trying to figure out is how to load those assemblies so that my digging into my objects will work properly. I understand that if those assemblies were in the GAC or in the directory of the running executable, I could just load them by their name, but that isn't likely to be the case for this use case and it's my primary use case.

这也正是我所期望的。但是,我想弄清楚的是如何加载这些程序集,以便我对对象的挖掘能够正常工作。我知道如果这些程序集在 GAC 或正在运行的可执行文件的目录中,我可以只按它们的名称加载它们,但对于这个用例来说不太可能是这种情况,它是我的主要用例。

So, what it boils down to is how do I load a given assembly and all of its arbitrary assemblies starting with a filename and resulting in a completely Reflection-browsable tree of types, properties, methods, etc.

所以,它归结为如何加载给定的程序集及其所有以文件名开头的任意程序集,并生成一个完全反射可浏览的类型、属性、方法等树。

I know that tools like Reflector do this, I just can't find the syntax for getting at it.

我知道像 Reflector 这样的工具可以做到这一点,我只是找不到实现它的语法。

采纳答案by Kent Boogaart

Couple of options here:

这里有几个选项:

  1. Attach to AppDomain.AssemblyResolveand do another LoadFilebased on the requested assembly.
  2. Spin up another AppDomainwith the directory as its base and load the assemblies in that AppDomain.
  1. 根据请求的程序集附加AppDomain.AssemblyResolve并执行另一个操作LoadFile
  2. AppDomain以该目录为基础启动另一个,并在其中加载程序集AppDomain

I'd highly recommend pursuing option 2, since that will likely be cleaner and allow you to unload all those assemblies after. Also, consider loading assemblies in the reflection-only context if you only need to reflect over them (see Assembly.ReflectionOnlyLoad).

我强烈建议采用选项 2,因为这可能会更干净,并允许您在之后卸载所有这些程序集。此外,如果您只需要对它们进行反射,请考虑在仅反射上下文中加载程序集(请参阅 参考资料Assembly.ReflectionOnlyLoad)。

回答by mathume

I worked out Kent Boogaart's second option. Essentially I had to:

我想出了Kent Boogaart的第二个选项。基本上我必须:

1.) Implement the ResolveEventHandlerin a separate class, inheriting from MarshalByRefObjectand adding the Serializableattribute.

1.)ResolveEventHandler在一个单独的类中实现,继承MarshalByRefObject并添加Serializable属性。

2.) Add the current ApplicationBase, essentially where the event handler's dll is, to the AppDomainPrivateBinPath.

2.) 将 current ApplicationBase,本质上是事件处理程序的 dll 所在的位置,添加到AppDomainPrivateBinPath.

You can find the code on github.

你可以在github上找到代码。