【问题标题】:Type exists in 2 assemblies类型存在于 2 个程序集中
【发布时间】:2012-02-08 13:44:49
【问题描述】:

我从两个不同的第三方 COM DLL 创建了两个 .NET 互操作程序集。两个 COM DLL 都包含一个名为 COMMONTYPE 的类型。因此,COMMONTYPE 现在也通过两个 Interop 程序集公开。

我有第三个项目需要使用这两个 Interop 程序集,我得到了臭名昭著的编译时错误:

<ABC> 类型在 <ASSEMBLY1.dll><ASSEMBLY2.dll> 中都存在

由于 COM DLL 由第三方供应商提供,我无法访问源代码,并且我正在编写 C# 控制台应用程序,这意味着我没有可以添加 @ 的 web.config 文件987654326@ 解决方法。我能做什么?

【问题讨论】:

  • 我来到这里是因为 Visual Studio 抱怨 Newtonsoft.Json.Torq 和 Newtonsoft.Json 中都存在 JsonConvert 类型

标签: c# com-interop


【解决方案1】:

我知道这是旧的,但有一个比列出的更简单的方法。当您引用具有确切相同名称和命名空间的类型的两个程序集时,此方法有效。

如果您右键单击对 DLL 的引用并选择属性,您将看到这里有一个名为“别名”的属性

默认值为“全局”。对于冲突的程序集之一,将其更改为任何其他值。在下面的示例中,我已将其从“全局”更改为“目的地”。

接下来,在您的代码文件中,您必须使用extern keyword 将此别名用作这些类型的根级命名空间。在此示例中,您将在 .cs 文件的顶部放置以下内容:

extern alias destination

现在,在此文件中,您可以引用这两种类型。

extern alias destination;
namespace Test
{
    public static class TestClass
    {
        public static void Success()
        {
            var foo = destination::Some.Duplicate.Namespace.SomeDuplicateType();
            var bar = Some.Duplicate.Namespace.SomeDuplicateType();
        }
    }
}

【讨论】:

  • 欣赏更好的答案!这显然是别名的基本用途
  • 对我来说也绝对是最佳答案。其他解决方案甚至不起作用,因为我有两个完全相同的 dll,一个只是与 ILMerge 合并到另一个中。问题解决了
  • 我想在这里再次向@bunkerdive 提出一个问题(最受欢迎的答案):您如何使用 NuGet 包进行此操作?如果您尝试更改 Alias VS 会给您一个错误:无法修改源自导入文件的评估对象
  • 我进入了参考,选择了 Nuget 安装的包,然后将别名设置为目标。像魅力一样工作......
  • @PedroGaspar 可能是因为您使用的是 Visual Studio“社区”。我在 VS2017 Enterprise 上,我刚刚在 5 秒前实现了这个。一些较低级别的 VS 版本对单元测试没有很好的支持。
【解决方案2】:

老问题,但找到了一个更简单的选择... 选择要使用的参考... 在属性下,将别名更改为“xyz” 现在在代码行的顶部添加:

extern alias xyz;

然后添加使用:

using xyz.VENDOR2.Type;

或其他使用方式:

using OtherNameSpace = xyz.VENDOR2.Type;

现在您应该可以像下面这样显式使用引用了:

var abc = new xyz.VENDOR2.Type.abc();

var abc = new OtherNameSpace.abc();

【讨论】:

  • 但是,当它是一个被引用的 NUGET 包而不是常规 dll 时,这可以实现吗?
  • @bunkerdive 无论有没有 NuGet 包,它很可能会以相同的方式工作。安装 NuGet 包时,对包中程序集的引用应自动添加到 Visual Studio 项目中。在“*解决方案资源管理器”视图窗格中查看您的项目下的 References 节点。
  • @bunkerdive 使用 NuGet 包和 VS2017,您不会在属性下获得别名选项。因此,您必须按照答案在 .csproj 文件中添加手动别名。通过<Target> 示例寻找答案。
【解决方案3】:

除非供应商的命名空间相同(不太可能),否则类型定义实际上是分开的。您需要做的(有时这是一个完整的 PITA)是在您的 using 语句中创建一个命名空间别名,而不是简单地应用语句全权委托。这将允许您重新识别命名空间:

using Vendor1 = Vendor.Namespace;
using Vendor2 = OtherVendor.Namespace;

...

Vendor1.COMMONTYPE blah = new Vendor1.COMMONTYPE();
Vendor2.COMMONTYPE blah2 = new Vendor2.COMMONTYPE();

这意味着为这些供应商的每个命名空间中的所有类型使用特定别名。

【讨论】:

  • 这肯定会帮助我解决编译时错误。但是在创建程序集时我是否可以做任何事情来使 .NET 忽略特定类型,这样我就只能在其中的 1 个程序集中使用通用类型..??
  • @KouSHal:唯一的方法是构建一个引用供应商库之一的包装类,并将所有类、扩展方法等作为代理公开。如果它是只有几个类的小型库,这不会太难,但如果它像大多数供应商库一样,这将是创建和维护的噩梦。
【解决方案4】:

我知道这是旧的,但我最近遇到了这个。我发现解决此问题的最佳方法是通过添加以下内容来修改 YourProjectName.csproj 文件:

<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
    <ItemGroup>
        <ReferencePath Condition="'%(FileName)' == 'Namespace.You.Want.To.Alias'">
            <Aliases>NewAliasForNamespace</Aliases>
        </ReferencePath>
    </ItemGroup>
</Target>

【讨论】:

    【解决方案5】:

    您可以为不同的命名空间和/或类型使用别名:

    如下所示:

    using other = sssssss.a;
    namespace ConsoleApplication1
    {
        public class a 
        {
            public string ff { get; set; }
        }
        class Program
        {
            static void Main(string[] args)
            {
                other s = new other();
                a b = new a();
            }
        }
    }
    namespace sssssss 
    {
    
        public class a
        {
            public string ff { get; set; }
        }
    }
    

    MSDN

    【讨论】:

      【解决方案6】:

      也许您可以通过更改其中一个程序集的 namespace 来欺骗它,在这种情况下,一个 COMMONTYPE 的完全限定名称将不等于另一个,可能它可以解决您在第三个 DLL 中发生冲突的问题。

      希望这会有所帮助。

      【讨论】:

      • 不幸的是我不能这样做,因为我正在使用 tlbimp 从现有的 COM dll 生成 .NET 程序集。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      • 1970-01-01
      相关资源
      最近更新 更多