谁能解释以下行为?

总而言之,如果您在Visual Studio 2008中创建多个兼容CLS的库,并让它们共享一个公共的名称空间根,则引用另一个库的库将需要对该库的引用进行引用,即使它不使用它们。

用一句话很难解释,但是这里是重现行为的步骤(请密切注意名称空间):

创建一个名为LibraryA的库,并向该库添加一个类:

namespace Ploeh
{
    public abstract class Class1InLibraryA
    {
    }
}


通过将[assembly: CLSCompliant(true)]添加到AssemblyInfo.cs,确保该库符合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,版本= 1.0.0.0,文化=中性,PublicKeyToken =空”的引用。


您可以使用以下方式之一重新编译解决方案:


从LibraryC删除CLS合规性
添加对LibraryA的引用(尽管您不需要)
更改LibraryC中的名称空间,使其不属于LibraryB的名称空间层次结构(例如,更改为Fnaah.Samples.LibraryC)
更改Class1InLibraryB的名称空间(即LibracyC中未使用的名称空间),使其不位于LibraryC的名称空间层次结构中(例如,更改为Ploeh.Samples.LibraryB)。


似乎在名称空间层次结构和CLS遵从性之间存在一些奇怪的相互作用。

解决方案可以通过选择上面列表中的一个选项来解决此问题,但是有人可以解释此现象的原因吗?

最佳答案

我查看了CLS(http://msdn.microsoft.com/en-us/netframework/aa569283.aspx)的正式文档,但是在找到简单答案之前,我的头突然爆炸了。

但是我认为这样做的基础是,为了验证LibraryC的CLS兼容性,编译器需要研究与LibraryA的可能命名冲突。

编译器必须验证所有“在定义程序集之外可访问或可见的类型的一部分”(CLS规则1)。

由于公共类Class1InLibraryC继承了Class2InLibraryB,因此它还必须验证对LibraryA的CLS遵从性,尤其是因为“ Ploeh。*”现在在CLS规则5的“范围内”。种”。

更改Class1InLibraryB或Class1InLibraryC的名称空间,使它们变得不同似乎可以说服编译器不再存在名称冲突的机会。

如果选择选项(2),则添加引用并进行编译,您将看到在生成的程序集元数据中未实际标记该引用,因此这仅是编译/验证时的依赖项。

10-05 18:12