【问题标题】:Need a way to reference 2 different versions of the same 3rd party DLL需要一种方法来引用同一个 3rd 方 DLL 的 2 个不同版本
【发布时间】:2012-07-18 01:20:11
【问题描述】:

我有一个包含 2 个项目的解决方案:Proj1 和 Proj2,其中 Proj1 是启动项目。

Proj1 引用 Proj2(为了调用 Proj2 的类)并且它的现有代码还引用了一个名为 A 的第 3 方 DLL,版本为 1.0.0.0。

Proj2 引用了相同的第 3 方 DLL A,但它在 2.0.0.0 版本中引用它,因为该项目中的类需要更新的实现,而 1.0.0.0 中没有。

到目前为止,我已经尝试了以下方法: 1.引用A时将“特定版本”切换为true 2.在Proj2中添加了一个名为“v2Folder”的文件夹并添加了一个v2.0.0.0,将其“复制到输出目录”设置为始终复制 3. 在app.config中添加“探测路径”以指向带有v2.0.0.0 DLL的子文件夹

我想要的是在普通 \bin\ 文件夹中看到 A v1.0.0.0,在 \bin\v2Folder 中看到 A v2.0.0.0,我希望当我运行 Proj1.exe 时,Proj1 是旧的代码依然会调用A v1.0.0.0的方法,只有在调用Proj2实现的时候才会调用A v2.0.0.0的方法。

问题是,当我构建我的解决方案时,v1.0.0.0 被 v2.0.0.0 取代,构建日志有类似“无法解决冲突”A,版本 = 2.0.0.0,文化=neutral, PublicKeyToken=blah”和“A, Version=1.0.0.0, Culture=neutral, PublicKeyToken=blah”。任意选择“A, Version=2.0.0.0, Culture=neutral, PublicKeyToken=blah”。

有人可以帮忙吗?

【问题讨论】:

  • 感谢阿德里亚诺的建议。我的问题是我希望我的应用在代码的不同部分使用这两个版本,即我想同时保留版本 1 和 2。
  • 为什么不升级 Proj1 以使用更新版本的 DLL "A"?不建议使用同一 DLL 的不同版本,如果不使用 AssemblyResolver 进行破解,实际上是不可能的。以下是描述 NuGet 如何在这种情况下帮助您的链接:blog.davidebbo.com/2011/01/…

标签: c# dll


【解决方案1】:

即使两个 dll 版本具有相同的公共令牌也是可以实现的。

实现这一点的步骤如下:

  • 确保将两个版本的dll复制到目标目录
    • 添加这两个dll作为项目的内容项
    • 为两者启用本地复制
  • 确保在编译时会引用两个版本的 dll
    • 在项目中添加两个dll作为引用
    • 禁用两者的本地复制

仅添加引用是不够的,因为只会复制较新的引用(即使您为两者都启用了本地复制)。 这给出了一个像这样的项目树:

  • 确保在编译时可以区分两个版本的dll
    • 为至少一个引用添加别名

  • 使用外部别名引用代码中的库(请参阅@drf response

此时您可以编译,但在运行时仍然存在问题。 要解决这些问题:

  • 编辑app.config 以添加assemblyBinding
    • assemblyIdentity 是相关的dll。
    • bindingRedirect 将版本范围 (oldVersion) 映射到固定版本 (newVersion)。
    • codeBase 将固定的 version 映射到文件路径 (href)。

bindingRedirect newVersioncodeBase version 必须匹配和匹配使用的dll的版本。

这里的一切都是关于the dll assembly version, not the file version

这是程序输出:

此 hack 源代码可在 here 获得。

编辑:正如sharpiro 评论的那样,在构建项目时仍然存在警告,这与this msbuild bug 有关,因为这个答案是一种解决方法。

【讨论】:

  • 我知道我们应该避免使用这样的 cmets,但感谢您提供此分步解决方案和示例库。太有用了。
  • 很好的答案和解决方案,但不幸的是,每当构建引用项目时,它都会创建 2 个构建警告
  • @Sharpiro 他们长什么样?编辑:Msbuild 错误:github.com/Microsoft/msbuild/issues/715
【解决方案2】:

这可以使用extern alias 功能实现。编译时,在 DLL 文件中包含一个别名,例如:

csc.exe ... /reference:AV1=v1.0.0.0/A.dll /reference:AV2=v2.0.0.0/A.dll

(这也可以在 Visual Studio 中通过更改引用的aliases 属性来设置。)

在 cs 文件中,您可以使用 extern alias 来引用命名空间:

extern alias AV1;
extern alias AV2;
// using statements

这允许您独立引用每个版本:

var v1foo = new AV1::Foo();
var v2foo = new AV2::Foo();

对于仅使用其中一个 DLL 的项目,您可以包含对所需版本的引用。

// ProjA cs file
extern alias AV1;
using Foo = AV1::Foo; // alternately, path to namespace
...
var foo = new Foo(); // from version 1 of library


// ProjB cs file
extern alias AV2;
using Foo = AV2::Foo; // alternately, path to namespace
...
var foo = new Foo(); // from version 2 of library

这允许在同一个解决方案中独立引用 DLL 的两个版本。 (MSDN Reference.)

【讨论】:

  • 感谢 drf 提供的示例代码。我刚才试了一下,除了我单独留下 Proj1(所以它的别名仍然在“全局”),并且只指定 Proj2 的代码使用“外部别名 AV2”。我还在我的 app.config 中添加了一个“probing privatePath="v12;"”,以便它知道从哪里加载 v12 DLL。在运行时,我仍然收到“FileLoadException”,说“无法加载文件或程序集 'A,Version=2.0.0.0, ....”。
  • 要修复运行时问题,您应该禁用自动绑定重定向 docs.microsoft.com/en-us/dotnet/framework/configure-apps/… 并在 App.config 中创建一个自定义的dependentAssembly 块,例如 github.com/Orace/Hacks.NET/blob/master/OneLibraryTwoVersions/…
【解决方案3】:

将第 3 方 dll 版本 2.0 重命名为 A_2.dll,并添加对重命名的 dll 的引用。

【讨论】:

  • 将不起作用,因为内部命名空间和类名保持不变,这将导致命名冲突
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-06
相关资源
最近更新 更多