我该如何动态引用一个查找另一个程序集的程序集?

6

对于这个问题我表示歉意,如果有更好的建议请告诉我,我很乐意改进。

我正在尝试通过动态调用属于另一个应用程序的程序集来创建一个对象。

以下PowerShell代码对我来说运行得很好:

[Reflection.Assembly]::LoadFrom("C:\Program Files\Vendor\Product\ProductAPI.dll")
$bobject = new-object ProductAPI.BasicObject    
$bobject.AddName("Some Name") 

我正在尝试用C#做同样的事情。根据StackOverflow上其他帖子的建议,我目前有以下代码:

System.Reflection.Assembly myDllAssembly =
System.Reflection.Assembly.LoadFile("C:\\Program Files\\Vendor\\Product\\ProductAPI.dll");

System.Type BasicObjectType = myDllAssembly.GetType("ProductAPI.BasicObject");

var basicObjectInstance = Activator.CreateInstance(BasicObjectType);

最后一行代码会导致TargetInvocationException异常。

{"无法加载文件或程序集'AnotherObject, Version=1.2.345.0, Culture=neutral, PublicKeyToken=null'或其其中一个依赖项。系统找不到指定的文件。"}

看起来BasicObject构造函数试图调用AnotherObject(从相同文件夹中的AnotherObject.dll中)但找不到它。

有没有什么提示可以解决这个问题?


我认为你正在加载的 DLL 需要另一个 DLL 才能正常工作。你可以使用这个工具来探索 DLL 的依赖关系。http://www.dependencywalker.com/ - Reactgular
当你找到缺失的DLL时,要么将其复制到发布文件夹中,要么修改Windows PATH以包含它。 - Reactgular
值得检查的是使用 FUSLOGVW.exe (程序集绑定日志查看器) 来查看哪些内容无法加载,它将展示给你正在失败的加载项(以及.NET加载器正在寻找的位置)。 - Richard
1
@MathewFoscarini .NET程序集加载器不直接使用PATH(原生dll加载器也是如此:或者至少不是直接的)。最好考虑*运行时如何定位程序集*。特别是通过“LoadFrom”加载的程序集位置在加载任何依赖项时都会包含。请参阅我的先前评论:首先要做的就是了解无法找到的内容。 - Richard
1
谢谢大家 - 看起来我只是没有意识到可执行文件基本上需要与我想要使用的应用程序在同一个文件夹中。 - gf131072
我知道AnotherObject.dll在哪里——它在包含ProductAPI.dll的文件夹中。我的可执行文件是否有办法存在于此文件夹之外,但告诉运行时将其添加到应用程序生命周期内的部分程序集路径(即仅名称)搜索列表中的位置之一? - gf131072
1个回答

8
如果在通常位置找不到依赖程序集,则需要手动指定如何找到它们。
我知道的两种最简单的方法是:
  1. 使用Assembly.Load提前手动加载依赖程序集。

  2. 处理加载程序集时具有附加程序集依赖项的域的AssemblyResolve事件。

这两种方法本质上都要求您事先了解要加载的程序集的依赖项,但我认为这并不是一个太大的要求。
如果您选择第一种选项,还值得了解完整加载和仅反射加载之间的区别。
如果你更愿意使用2(我推荐这个),你可以尝试类似于以下的东西,它还有一个额外的好处,即可以与嵌套依赖链一起使用(例如MyLib.dll引用LocalStorage.dll引用Raven.Client.dll引用NewtonSoft.Json.dll),并且还会提供关于找不到哪些依赖项的信息:
AppDomain.CurrentDomain.AssemblyResolve += (sender,args) => {

    // Change this to wherever the additional dependencies are located    
    var dllPath = @"C:\Program Files\Vendor\Product\lib";

    var assemblyPath = Path.Combine(dllPath,args.Name.Split(',').First() + ".dll");

    if(!File.Exists(assemblyPath))
       throw new ReflectionTypeLoadException(new[] {args.GetType()},
           new[] {new FileNotFoundException(assemblyPath) });

    return Assembly.LoadFrom(assemblyPath);
};

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