gpt4 book ai didi

c# - 使用反射从外部程序集实例化一个类

转载 作者:太空狗 更新时间:2023-10-30 01:01:14 24 4
gpt4 key购买 nike

我目前正在尝试开发一种使用反射以编程方式在外部项目中运行测试类的方法。这是应该展示我的问题的简化代码块。

string pathToDLL = @"C:\Path\To\Test\Project\UnitTests.dll";
IEnumerable<Type> testClasses = assembly.GetExportedTypes();
Type testClass = testClasses.First();
object testClassInstance = assembly.CreateInstance(testClass.FullName);

此代码抛出以下异常:

'assembly.CreateInstance(testClass.FullName)' threw an exception of type 'System.Reflection.TargetInvocationException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146232828
HelpLink: null
InnerException: {System.IO.FileNotFoundException: Could not load file or assembly 'Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'Project.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
at Project.UnitTests.TestClass..ctor()}
Message: "Exception has been thrown by the target of an invocation."
Source: "System.Private.CoreLib"
StackTrace: " at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)\r\n at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, Boolean nonPublic)\r\n at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)\r\n at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)\r\n at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)\r\n at System.Reflection.Assembly.CreateInstance(String typeName)"

在堆栈跟踪中,它声明它“无法加载文件或程序集‘Project.Core...’”。

此项目是目标 DLL 直接引用的项目(它测试的项目)。有谁知道为什么这不能自动获取这些 DLL?


我研究了解决这个问题的方法:

  1. 这可能是 dll 的编译方式 - 这可以更改,因为我可以控制它 - 目前是通过运行 dotnet build */*/project.json 在解决方案级别。这成功编译了所有内容,并且所有相关的 DLL 似乎都填充在 bin 文件夹中。我还调查了是否更改为 dotnet publishdotnet build */*/project.json --configuration Release,但似乎都没有帮助。

  2. 我也研究过使用不同的编译方法,例如 Activator.CreateInstance 再次没有骰子。

  3. 我似乎没有找到将多个 DLL 加载到同一个 Assembly 类中以便控制引用的方法。由于 AppDomains 已从 .NET Core 中删除,这看起来不太可能,尽管我可能弄错了/看错了区域。


如果我正在做的事情看起来不太可能,有谁知道是否可以使用其他方法实现这种功能? IE。罗斯林?

最佳答案

我只是想我会用我设法找到的解决方案来更新这个问题,以防其他人遇到与我相同的问题。不过我要感谢@Emrah Süngü 为我指明了正确的方向。

Emrah 提醒我,我需要导入要加载的 DLL 的依赖项,以便调用存储在其中的类。一种方法是扩展您的 app.config 以导入这些依赖项 - 但是我想在运行时执行此操作(对于我不知道在启动程序之前要运行的项目)所以我需要寻找其他解决方案。

如果您不使用 .NET Core,这相对简单,因为 AppDomains可用于加载所有依赖项并执行您的代码。然而,由于这已经是removed from .NET Core我需要找到另一个兼容的解决方案。

我考虑过运行一个单独的进程(或 Powershell)并更改工作目录的想法,以便该进程在存储其所需的所有依赖项的目录中运行。但是,我找不到一种方法可以让我对运行这些方法的结果使用react。

后来我研究了如何操纵 AssemblyLoadContext类,但是 ( at the time of writing ) 几乎没有关于此类的文档。我确实找到了这个能够显着帮助的答案...... https://stackoverflow.com/a/37896162/6012159

为了让它工作,我确实不得不做一点小改动,而不是每次都创建一个新的 AssemblyLoader(这会导致在尝试调用程序集内的方法时抛出异常),我每次都重用了 AssemblyLoader (这消除了这个问题)。

public class AssemblyLoader : AssemblyLoadContext
{
private string folderPath;

public AssemblyLoader(string folderPath)
{
this.folderPath = folderPath;
}

protected override Assembly Load(AssemblyName assemblyName)
{
var deps = DependencyContext.Default;
var res = deps.CompileLibraries.Where(d => d.Name.Contains(assemblyName.Name)).ToList();
if (res.Count > 0)
{
return Assembly.Load(new AssemblyName(res.First().Name));
}
else
{
var apiApplicationFileInfo = new FileInfo($"{folderPath}{Path.DirectorySeparatorChar}{assemblyName.Name}.dll");
if (File.Exists(apiApplicationFileInfo.FullName))
{
return this.LoadFromAssemblyPath(apiApplicationFileInfo.FullName);
}
}
return Assembly.Load(assemblyName);
}
}

可用于加载这样的程序集:

string directory = @"C:\Path\To\Project\bin\Debug\netcoreapp1.0\publish\";

string pathToDLL = @"C:\Path\To\Project\bin\Debug\netcoreapp1.0\publish\project.dll";

AssemblyLoader al = new AssemblyLoader(directory);

Assembly assembly = al.LoadFromAssemblyPath(pathToDLL);

关于c# - 使用反射从外部程序集实例化一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40565508/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com