任何人可以解释以下行为吗?
总之,如果在Visual Studio 2008中创建多个 CLS兼容的库并让它们共享一个公共命名空间根,则引用另一个库的库将要求引用该库库的引用,即使它不消耗它们。
用一句话解释起来相当困难,但这里是重现行为的步骤(密切注意命名空间):
创建一个名为LibraryA的库,并向该库添加一个类:
namespace Ploeh
{
public abstract class Class1InLibraryA
{
}
}
通过向AssemblyInfo.cs添加[assembly: CLSCompliant(true)]
,确保该库符合CLS。
创建另一个名为LibraryB的库并引用LibraryA。将以下类添加到LibraryB:
namespace Ploeh.Samples
{
public class Class1InLibraryB : Class1InLibraryA
{
}
}
和
namespace Ploeh.Samples
{
public abstract class Class2InLibraryB
{
}
}
确保LibraryB也符合CLS。
请注意,Class1InLibraryB派生自LibraryA中的类型,而Class2InLibraryB则不派生。
现在创建一个名为LibraryC的第三个库,并引用LibraryB(但不是LibraryA)。添加以下类:
namespace Ploeh.Samples.LibraryC
{
public class Class1InLibraryC : Class2InLibraryB
{
}
}
这应该仍然可以编译。请注意,Class1InLibraryC派生自LibraryB中的类,不使用LibraryA中的任何类型。
另请注意,Class1InLibraryC是在名称空间中定义的,该名称空间是LibraryB中定义的名称空间层次结构的一部分。
到目前为止,LibraryC没有引用LibraryA,因为它不使用LibraryA中的任何类型,所以解决方案会编译。
现在也使LibraryC CLS兼容。突然,解决方案不再编译,给你这个错误信息:
“Ploeh.Class1InLibraryA”类型是在未引用的程序集中定义的。您必须添加对程序集'Ploeh,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'的引用。
您可以通过以下方式之一再次编译解决方案:
似乎命名空间层次结构和CLS合规性之间存在一些奇怪的相互作用。
解决此问题可以通过选择上面列表中的一个选项来完成,但任何人都可以解释此行为背后的原因吗?
答案 0 :(得分:19)
我查看了CLS的正式文件(http://msdn.microsoft.com/en-us/netframework/aa569283.aspx),但在我找到一个简单的答案之前,我的头部爆炸了。
但我认为基础是编译器为了验证LibraryC的CLS合规性,需要研究与LibraryA的可能命名冲突。
编译器必须验证在定义程序集之外可访问或可见的所有“类型的部分”(CLS规则1)。
由于公共类Class1InLibraryC继承了Class2InLibraryB,因此它必须验证对LibraryA的CLS合规性,特别是因为“Ploeh。*”现在是“在范围内”的CLS规则5“在符合CLS的范围中引入的所有名称应独立于种类“。
更改Class1InLibraryB或Class1InLibraryC的命名空间以使它们变得不同似乎说服编译器不再存在名称冲突的可能性。
如果选择选项(2),添加引用并编译,您将看到引用实际上没有标记在生成的汇编元数据中,因此这只是一个编译/验证时依赖。
答案 1 :(得分:7)
答案 2 :(得分:1)
问题在Roslyn中得到修复,可在Visual Studio 14中使用 截至2014年7月,目前的CTP可用here 有关详细信息,请参阅this bug report。