引用同一 DLL 的多个版本
Reference multiple versions of the same DLL
我有一个项目需要间接使用三个不同版本的第三方库。这些版本彼此不兼容,所以我不能使用绑定重定向 - 它必须是准确的 .dll
文件。 (库是 Spire.Doc, Spire.XLS & Spire.PDF;Spire.PDF DLL 被所有三个引用)
我已将这三个组件分离到单独的包装器项目中,并创建了 类,它包装了对库中任何内容的直接引用。但是,这并没有解决我的问题:'consuming' 项目仍然必须将所有库复制到 bin
文件夹才能 运行。构建过程不知道要复制哪个版本,所以只复制最新的版本。由于存在错误的 DLL,这给了我 运行 时间异常。
我有什么considered/tried:
- 添加绑定重定向到特定版本(运行时间异常,因为没有找到库的确切版本)
- 使用 post-build 步骤合并包装器项目(再次出现 运行time 异常,抱怨缺少库 DLL)
- 为应用程序的每个部分创建单独的控制台应用程序,然后单独调用它们 - 这是一个复杂的最后手段,我真的不想这样做!
我读到 extern alias 可能会有所帮助 - 但据我所知,您只能区分具有不同名称的程序集。 Spire.PDF 库在每个项目中具有相同的名称(以及相同的签名 public 令牌)。
如何在同一解决方案中独立使用这三个不同版本的库?
编辑:
此问题与建议的重复问题略有不同,因为我无法更改依赖库中的任何代码。 Spire.Doc 依赖于 Spire.PDF 到 Spire.XLS
的不同版本
在您的消费项目(项目 A)中,创建一个通用接口 (ISpiroPdfAlex
),它包含外部程序集的 3 个版本提供(以及您使用)的所有功能。您不能以任何方式从这些包装器中引用 Project A 中的 anything ,否则您会创建一个依赖项,这就是您要尝试的避免。
让所有 3 个包装器项目导入 项目 A 并实施 ISpiroPdfAlex
。这将使您能够通过相同的 API 调用 3 个不同版本中的每一个。
在此之后,在 Project A 下为每个版本创建一个子文件夹(因此总共有 3 个子文件夹)- 因为 Project A 有没有引用任何外部程序集,它不能自己加载它们——当你需要正确的版本时,你必须手动加载它们。由于您的外部 DLL 可能具有同名的依赖项,因此它们不能全部位于同一文件夹中(如您所写),这就是您需要子文件夹的原因。
在 运行 时,当您需要这些版本之一时,您可以调用 Assembly.LoadFile
to load a specific version of your assembly from the specified folder and then you can either use Activator.CreateInstance
或依赖注入来创建实现您的接口的 class 实例。拥有实例后,您可以自由调用任何函数,并且您将获得依赖于版本的行为。
编辑:
OP 在评论中提到,不是他的代码依赖于不同版本的 PDF 库,而是他的代码依赖的其他第 3 方 Spire 库。
在这种情况下,无法修改第 3 方代码以支持程序集的动态加载,并且它们已经具有二进制依赖项。不可能将不同版本的 "same" 程序集加载到同一进程中,尤其是你提到这些版本甚至不能相互向后兼容。
在这种情况下,我能想到的唯一解决方案是将所有相关功能分解为单独的控制台应用程序(每个不同版本一个),并通过命令行调用这些单独的 .exe-s。
要传递信息,您可以直接在命令行上传递数据,也可以通过stdin
传递数据。或者,您可以只传递一个临时文件的名称,该文件包含执行某些处理所需的所有数据。要从控制台进程获取 return 数据,您可以读取其 stdout
或使用相同/不同的文件。
这样一来,您的主进程就不会加载这些程序集中的任何一个,也不会依赖它们 - 每个控制台应用程序只依赖一个版本,因此不会发生冲突。
我有一个项目需要间接使用三个不同版本的第三方库。这些版本彼此不兼容,所以我不能使用绑定重定向 - 它必须是准确的 .dll
文件。 (库是 Spire.Doc, Spire.XLS & Spire.PDF;Spire.PDF DLL 被所有三个引用)
我已将这三个组件分离到单独的包装器项目中,并创建了 类,它包装了对库中任何内容的直接引用。但是,这并没有解决我的问题:'consuming' 项目仍然必须将所有库复制到 bin
文件夹才能 运行。构建过程不知道要复制哪个版本,所以只复制最新的版本。由于存在错误的 DLL,这给了我 运行 时间异常。
我有什么considered/tried:
- 添加绑定重定向到特定版本(运行时间异常,因为没有找到库的确切版本)
- 使用 post-build 步骤合并包装器项目(再次出现 运行time 异常,抱怨缺少库 DLL)
- 为应用程序的每个部分创建单独的控制台应用程序,然后单独调用它们 - 这是一个复杂的最后手段,我真的不想这样做!
我读到 extern alias 可能会有所帮助 - 但据我所知,您只能区分具有不同名称的程序集。 Spire.PDF 库在每个项目中具有相同的名称(以及相同的签名 public 令牌)。
如何在同一解决方案中独立使用这三个不同版本的库?
编辑:
此问题与建议的重复问题略有不同,因为我无法更改依赖库中的任何代码。 Spire.Doc 依赖于 Spire.PDF 到 Spire.XLS
的不同版本在您的消费项目(项目 A)中,创建一个通用接口 (ISpiroPdfAlex
),它包含外部程序集的 3 个版本提供(以及您使用)的所有功能。您不能以任何方式从这些包装器中引用 Project A 中的 anything ,否则您会创建一个依赖项,这就是您要尝试的避免。
让所有 3 个包装器项目导入 项目 A 并实施 ISpiroPdfAlex
。这将使您能够通过相同的 API 调用 3 个不同版本中的每一个。
在此之后,在 Project A 下为每个版本创建一个子文件夹(因此总共有 3 个子文件夹)- 因为 Project A 有没有引用任何外部程序集,它不能自己加载它们——当你需要正确的版本时,你必须手动加载它们。由于您的外部 DLL 可能具有同名的依赖项,因此它们不能全部位于同一文件夹中(如您所写),这就是您需要子文件夹的原因。
在 运行 时,当您需要这些版本之一时,您可以调用 Assembly.LoadFile
to load a specific version of your assembly from the specified folder and then you can either use Activator.CreateInstance
或依赖注入来创建实现您的接口的 class 实例。拥有实例后,您可以自由调用任何函数,并且您将获得依赖于版本的行为。
编辑:
OP 在评论中提到,不是他的代码依赖于不同版本的 PDF 库,而是他的代码依赖的其他第 3 方 Spire 库。
在这种情况下,无法修改第 3 方代码以支持程序集的动态加载,并且它们已经具有二进制依赖项。不可能将不同版本的 "same" 程序集加载到同一进程中,尤其是你提到这些版本甚至不能相互向后兼容。
在这种情况下,我能想到的唯一解决方案是将所有相关功能分解为单独的控制台应用程序(每个不同版本一个),并通过命令行调用这些单独的 .exe-s。
要传递信息,您可以直接在命令行上传递数据,也可以通过stdin
传递数据。或者,您可以只传递一个临时文件的名称,该文件包含执行某些处理所需的所有数据。要从控制台进程获取 return 数据,您可以读取其 stdout
或使用相同/不同的文件。
这样一来,您的主进程就不会加载这些程序集中的任何一个,也不会依赖它们 - 每个控制台应用程序只依赖一个版本,因此不会发生冲突。