使用同一DLL的多个版本

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用同一DLL的多个版本相关的知识,希望对你有一定的参考价值。

我的任务是为应用程序创建一个新模块,因此,我正在为项目添加新的DLL。这一切都很好。

但是,在我的DLL中,我想使用新版本的外部DLL(我无法控制)。如果我只引用新的DLL并仅使用该DLL,我的代码将起作用,但旧代码将停止运行。

Could not load file or assembly 'itextsharp, Version=5.0.6.0, Culture=neutral,
PublicKeyToken=8354ae6d2174ddca' or one of its dependencies. The located assembly's
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)

我尝试过一个改变DLL名称的简单技巧,但这显然对我来说太天真了,认为它会起作用。我尝试使用外部别名(通过在我的引用中定义它们),但我仍然不知道如何将两个具有相同名称的文件放入一个BIN文件夹中...

我该怎么办?

答案

你可以load another version into a specific AppDomain

可能过于详细,但这篇文章演示了如何在有用的设置中使用AppDomains以及它们如何工作:

http://msdn.microsoft.com/en-us/magazine/cc164072.aspx

从非常基本的意义上讲,它归结为以下示例代码:

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    ...

    static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        if (/*some condition*/)
            return Assembly.LoadFrom("DifferentDllFolder\\differentVersion.dll");
        else
            return Assembly.LoadFrom("");
    }
另一答案

假设您有一个项目结构如下:

...其中AB是类库,C是可执行类型的项目(例如单元测试或控制台项目)。

我们假设文件夹结构是这样的:

ABC.sln
A/A.csproj
A/...
B/B.csproj
B/...
C/C.csproj
C/...
lib/thirdparty4/thirdparty.dll
lib/thirdparty5/thirdparty.dll

如果我们试图天真地一起引用我们的项目,我们就会遇到一个问题:两个版本的thirdparty.dll将被复制到同一个文件夹(C的输出(即bin)目录中)。我们需要一种方法让C将两个dll复制到其输出目录中,并提供一种引用其中任何一个的机制。

为了解决这个问题,我修改了C.csproj以包含以下内容:

<ItemGroup>
  <Content Include="..\lib\thirdparty4\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty4\thirdparty.dll</Link>
  </Content>
  <Content Include="..\lib\thirdparty5\thirdparty.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Link>thirdparty5\thirdparty.dll</Link>
  </Content>
</ItemGroup>

这将指示它在其输出目录中创建thirdparty4\thirdparty.dllthirdparty5\thirdparty.dll

现在,在构建C之后,其输出目录如下所示:

C\bin\Debug\A.dll
C\bin\Debug\B.dll
C\bin\Debug\C.dll
C\bin\Debug\thirdparty4\thirdparty.dll
C\bin\Debug\thirdparty5\thirdparty.dll

为了指示C使用这两个dll,我添加了一个App.config文件,其中包括:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="4.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
        <codeBase version="4.0.0.0" href="thirdparty4\thirdparty.dll" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
        <bindingRedirect oldVersion="5.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
        <codeBase version="5.0.0.0" href="thirdparty5\thirdparty.dll" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

这将指示程序集根据需要的版本使用一个DLL或另一个DLL,这两个DLL都将在输出目录的子文件夹中可用。 (bindingRedirect元素是可选的,但如果您需要一系列修订版本,则可以使用它们。)

另一答案

另一个可行的选择是使用extern,如下所述:

http://blogs.msdn.com/b/abhinaba/archive/2005/11/30/498278.aspx

另一答案

如果AppDomains解决方案不适用于您的情况,那么您将面临时间压力,有相互冲突的要求(就像曾经发生的那样),并且不介意荒谬可笑的黑客攻击:

  • 使用ildasm工具(Visual Studio附带的Developer Command Prompt的一部分)反编译较新版本的程序集
  • 编辑生成的.il文件以查找/替换程序集命名空间引用。使用引用的示例,这将是从itextsharp.X到itextsharp.new.X的更改
  • 同样,编辑AssemblyTitleAttribute的值。这需要将ASCII字符转换为十六进制。
  • 使用ilasm重新编译.il文件
  • 请注意,对于任何依赖程序集可能需要重复此操作(例如 - someassembly.core.whatever)
  • 使用不同的名称将新的.dll添加到项目中并显式引用它们(而不是通过nuget或其他)

嘿,不要那样看着我。我确实说过可笑的恶作剧......

另一答案

您还可以依赖于强命名程序集的程序集绑定重定向,如http://msdn.microsoft.com/en-us/library/2fc472t2.aspx中所述。

您只有一个版本的文件(最新版本),两个引用都将解析它。

以上是关于使用同一DLL的多个版本的主要内容,如果未能解决你的问题,请参考以下文章

如果在同一个 AppDomain 中加载了多个版本,WPF 无法选择正确的 DLL

如何在多个页面使用同一个HTML片段

Chrome-Devtools代码片段中的多个JS库

如何让多个PHP版本在同一个Apache服务下并存

多个用户访问同一段代码

在同一个片段中实现多个事件监听器 - Android