使用具有相同名称和相同命名空间的两个DLL

15

我有一个项目需要引用两个同名的DLL文件,这些DLL文件没有强名称且名称完全相同。

我需要访问每个DLL文件中的一些类型,但是这些类型具有完全相同的限定名称。比如说第一个DLL文件是companyDLL.dll,其中包含someProduct.Type1,而第二个DLL文件也是companyDLL.dll,同样包含someProduct.Type1

在同一个项目中如何访问这两个Type1类呢?

我已经尝试使用extern alias,但这要求我更改一个DLL文件的名称。


8
这完全属于“如果你试图这样做,那么你的设计严重有问题”的范畴。 - cdhowie
绝对同意,这是为一个工具而设计的,该工具需要来自公司产品的两个版本的信息(使用.NET构建)。但是,在这里涉及的产品是受监管的,因此不能更改。 - varosh
1
@cdhowie 不一定。涉及到旧版本和新版本之间的转换,或者例如基准比较等不同的场景有很广泛的范围。 - BartoszKP
5个回答

12
如果你的两个DLL文件名称相同,你需要将它们重命名。例如,Assembly1.dll和Assembly2.dll。
像通常一样将这些DLL文件添加到项目引用中,并在每个引用的属性中指定别名。
在使用DLL文件时,使用extern alias来指定要引用的DLL文件。
extern alias Assembly1Reference;
using Assembly1Reference::AssemblyNamespace.MyClass;
如果您保留现有设置,很可能会收到“FileNotFoundException”错误,指出无法加载文件或程序集。要修复此问题,您需要添加一个“ResolveEventHandler”,以加载您正在尝试使用的正确程序集。为此,您必须明确指定存储DLL文件的位置。在下面的示例中,我手动将Dll文件复制到项目的调试文件夹中。在“assembly1的名称”处,您可以在引用DLL、构建项目并使用记事本打开csproj文件后找到名称。要查找的内容将显示在我的示例代码下方。
extern alias Assembly1Reference;
extern alias Assembly2Reference;

static void Load()
{
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Do();
}

static void Do()
{
    new Assembly1Reference.Assembly.Class();
    new Assembly2Reference.Assembly.Class();
}

static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string currentPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
    if(args.Name == "Name of assembly1")//Found in csproj file after referenced and built
    {
        return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(currentPath, "Assembly1.dll"));
    }
    if(args.Name == "Name of assembly2")//Found in csproj file after referenced and built
    {
        return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(currentPath, "Assembly2.dll"));
    }
    return null;
}

如承诺的那样,这是在csproj文件中的引用的样子。 名称是包含在include属性中的所有内容。

<Reference Include="MyAssembly_3.6.2.0, Version=3.6.2.0, Culture=neutral, PublicKeyToken=12341234asdafs43, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>Resources\Assembly1.dll</HintPath>
      <Aliases>Assembly1Reference</Aliases>
</Reference>

我知道现在已经晚了,但希望这篇文章能帮助从现在开始来到这个页面的任何人。


这很有用,我可以部分地使其工作,但我有以下问题。这是什么目的?static void Do() { new Assembly1Reference.Assembly.Class(); new Assembly2Reference.Assembly.Class(); } 此外,通过代码解析程序集的优点是什么,而不是通过app.config像这样。在我的情况下,总是加载最新版本的程序集。我该怎么做才能加载特定重命名程序集的确切dll。 - Rajaraman Subramanian

3

使用 extern alias 来引入不同命名空间的程序集。如果你能区分命名空间,你应该可以使用 using altType1 = someProduct.Type1 为类型创建本地别名。

首先从命令行中限定程序集:

/r:ProductA=companyDLLA.dll
/r:ProductB=companyDLLB.dll

然后使用 extern alias 引用它们:

extern alias productA;
extern alias productB;

最后,您可以为本地类型设置别名:

using productTypeA = productA.Type1;
using productTypeB = productB.Type1;

不幸的是,这两个dll文件具有相同的名称。即/r:ProductA = companyDLLA.dll /r:ProductB = companyDLLA.dll - varosh
你不能重命名DLL的原因是什么?如果我处在你的情况下,我会尝试将它们重命名为companyDLLv1.dllcompanyDLLv2.dll - Greg Buehler
是的,DLL文件不能被重命名。这里所涉及的DLL文件是受到监管的,如果没有经过官方批准流程是无法更改的(而在我的情况下这是不可能的)。 - varosh

0
当我遇到这个问题时,我创建了两个不同的包装项目,每个项目引用不同版本的dll,并使用Costura.Fody nuget将dll嵌入到包装项目中,以防止构建冲突。

0

对我来说,没有任何一个提出的解决方案有效。我不得不重新编译DLL并给它们不同的标识,即在项目设置中更改“程序集名称”。

如果您无法重新编译DLL,则另一种解决方案是创建具有适当名称的包装器。


0

我能想到两种处理这个问题的方法。

  1. 将每个DLL加载到单独的AppDomain中。您将不得不跨AppDomain边界调用各种属性和方法。

  2. 在加载程序集之前,将每个程序集反汇编,然后重新组装并放入唯一的(可能是动态生成的)命名空间中。有一些工具可以帮助完成这项工作(1)(2)。您可以潜在地自动化它。

但我的基本感觉是,你真的不应该这样做。更容易解决这个问题的方法是在编译程序集之前解决它。


Cecil可能比ildasm更好,因为您可以使用C#直接操作IL。 - cdhowie
对于上述问题#1:我如何在同一项目中添加两个同名的DLL引用? - varosh

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