(请随意为此问题建议更准确的标题。)
在我的Visual Studio 2015解决方案中,我有三个项目(让我们称之为Alpha,Beta和Gamma)或多或少相同,但不同之处在于它们定义了不同的后端。这两个项目都将一个类热插入同一个命名空间:
α
namespace SharedNamespace {
public class SharedClass {
// implement SharedClass using Alpha's backend
}
}
β
namespace SharedNamespace {
public class SharedClass {
// implement SharedClass using Beta's backend
}
}
伽玛:
namespace SharedNamespace {
public class SharedClass {
// implement SharedClass using Gamma's backend
}
}
有几个项目使用这个热插拔类,每个类都引用Alpha,Beta或Gamma。其中一个(我们称之为 Omricon )用于引用Alpha,但现在引用了Gamma:
// ...
SharedNamespace.SharedClass sharedClass;
sharedClass.DoThing();
// ...
但是,当我尝试构建Omricon时,C#编译器会给出错误CS0433:
The type 'SharedClass' exists in both 'Alpha, Version=0.0.0.0 (etc)'
and 'Gamma, Version=0.0.0.0 (etc)'
然而,Omricon 仅在构建Gamma时引用Gamma - 当我进入项目引用列表时,仅出现对Gamma的引用。据我了解,Omricon应该完全知道关于Alpha的 nothing ,更不用说它在同一个位置定义了一个类。只有Omricon无法构建 - 其他使用Alpha和Beta的项目工作正常,当我将Omricon切换回使用Alpha时,它也可以正常工作!
在我看来,正在维护对Alpha的引用,然后在其他地方。如何在我的代码中找到对Alpha的迷路引用,并将其删除?
请注意,我已尝试强制完全重建(建议this answer),同样的错误仍然出现,因此它与坏对象缓存无关。
编辑:澄清了倒数第二段
答案 0 :(得分:15)
首先,你可能已经意识到:这是一个可怕的情况。如果您可以避免在两个不同的程序集中使用相同的命名类,并引用它们,则避免这种情况。它强烈表明您的应用程序存在架构缺陷。听起来我应该在第四个程序集中定义一个接口,然后让所有程序集同意使用该接口。
但是, 是一种在C#中处理这种情况的方法。
编译Omicron时,应该为Alpha.dll,Beta.dll和Gamma.dll提供参考别名:
/reference:AlphaDLL=Alpha.DLL /reference:BetaDLL=Beta.DLL ... etc
然后在Omicron里面说:
extern alias AlphaDLL;
extern alias BetaDLL;
extern alias GammaDLL;
在文件中,然后在该文件中,您可以说:
AlphaDLL::SharedNamespace.SharedClass
以消除意图使用哪一个。
但同样,不会陷入这种情况。而是创建一个SharedClass实现的接口,并使Alpha,Beta和Gamma实现都使用名称不冲突的类实现该接口。
答案 1 :(得分:1)
所以,在与队友进行了一些挖掘之后,我发现即使项目文件本身没有找到Alpha的引用,我们的一个.targets
文件指示MSBuild添加一个项目引用我背后的阿尔法:
<Choose>
<When Condition=" <!-- needs beta --> ">
<ItemGroup>
<ProjectReference Include="$(absdtSln)path\to\Beta">
...
</ProjectReference>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<ProjectReference Include="$(absdtSln)path\to\Alpha">
...
</ProjectReference>
</ItemGroup>
</Otherwise>
</Choose>
(我认为,这是因为参考Alpha和Beta的项目不必手动执行,正如我试图做的那样,并且是在我正在测试的项目上明确完成的。)
我为Gamma添加了另一个案例,现在情况正常。
(是的,@Eric,这样的事情是另一个证明这是一个可怕的情况。)
答案 2 :(得分:0)
具有相同名称的类可以存在于不同的项目中,但它们不能属于同一名称空间。
既然你说Alpha和Beta已经成功构建并且在添加Gamma时问题就开始了,我怀疑Alpha和Beta是通过在构建另一个时禁用一个而单独构建的,反之亦然。与团队中的某个人核实他们过去是如何建立的。
我认为设置背后的原因是你创建了两个具有相同类名的dll(Alpha和Beta),因此可以以相同的方式调用和使用它们。这会创建两个具有相同签名的dll来执行不同的操作。
你的消息在某种程度上证实了我的怀疑,因为你得到了Alpha和Gamma的问题,但不是Beta。我认为当您添加Gamma时,Beta已被禁用以准备构建Alpha。
答案 3 :(得分:-1)
正如评论中的其他人所说的那样,你所做的事情是不可能的......你不能在完全相同的命名空间中有两个具有完全相同名称的类(除非它们是部分的)。
你有几个选择:
好处是您没有这些冲突,并且可以通过其完全限定的命名空间指定您的类实例。
<强>α强>
namespace AlphaNamespace {
public class SharedClass {
// implement SharedClass using Alpha's backend
}
}
<强>β强>
namespace BetaNamespace {
public class SharedClass {
// implement SharedClass using Beta's backend
}
}
<强>伽玛:强>
namespace GammaNamespace {
public class SharedClass {
// implement SharedClass using Gamma's backend
}
}
这里,omicron将使用gamma作为
var gamma = new GammaNamespace.SharedClass(...)
当编译器将两个类合并在一起时,您必须合并项目并更改方法名称以避免冲突。怀疑这会按你想要的方式工作......
<强>α强>
namespace SharedNamespace {
public partial class SharedClass {
// implement SharedClass using Alpha's backend
}
}
<强>β强>
namespace SharedNamespace {
public partial class SharedClass {
// implement SharedClass using Beta's backend
}
}
<强>伽玛:强>
namespace SharedNamespace {
public partial class SharedClass {
// implement SharedClass using Gamma's backend
}
}
在这里,您将确定要使用的BaseClass的哪个扩展名(Alpha,Beta或Gamma),并通过依赖注入或某种逻辑确定来交换它。
namespace SharedNamespace {
public class BaseClass{
// place method abstractions here
}
}
namespace SharedNamespace {
public class AlphaClass : BaseClasse {
// implement BaseClass using Alpha's backend
}
}
namespace SharedNamespace {
public class BetaClass : BaseClasse {
// implement BaseClass using Beta's backend
}
}
namespace SharedNamespace {
public class GammaClass : BaseClasse {
// implement BaseClass using Gamma's backend
}
}