使用名称空间时 C# 编译的内容

What C# compiles when using namespaces

我们有两个应用程序,每个应用程序都编译自己的代码,并共享一些代码(主要是数据相关的)。将此设计拆分为三个命名空间并尝试强制执行该命名空间 Foo 永远不会导入命名空间 Bar 但两者都可以导入命名空间 Shared.

感觉很自然

我希望维恩图作为一种可视化方式受到赞赏:

但是 FooBar 之间的 class 中的一个从裂缝中溜走了,有人在 Foo 中引用了 Bar 中的 class =] 尽管强制执行。

这让我想知道 C# 编译器实际上是如何处理这个问题的?在我看来,可能会发生以下两种情况之一。

  1. 整个命名空间被编译成 Foo。让图表看起来像这样:
  2. 或者编译器足够聪明,可以提取必需的 class。使图表看起来像这样:

我似乎找不到任何关于 usings 和命名空间如何编译的文档。命名空间似乎只是为开发人员而不是编译器组织代码。然而他们提供了范围......所以我想#2适用吗?如何测试这个?

命名空间和程序集之间没有对应关系:一个程序集可能包含多个命名空间,一个命名空间可能跨越多个程序集。

程序集中编译的 IL 代码通过完全限定名称引用类型:Foo.SomeClass 而不是 SomeClassBar.OtherClass 而不是 OtherClass,等等.编译器的工作是在编写缩写形式 SomeClass 时找出 哪个 完全限定的类型名称 - 因为您可以定义一个 class 调用SomeClass 在命名空间 FooBar 甚至 System!

当你写:

namespace Foo
{
    public class SomeClass
    {
    }
}

您正在定义一个具有完全限定名称的类型 Foo.SomeClass

当你写:

using Foo;
...
SomeClass instance = new SomeClass();

编译器将其视为:

Foo.SomeClass instance = new Foo.SomeClass();

命名空间只是为了方便组织这些完全限定名称而构造的。当您说 using Foo; 时,您只是告诉编译器在您键入 SomeClass 时搜索以 Foo. 开头的完全限定名称。当你写 using Foo; 时,没有什么是 "imported",它只是提供了一个方便的替代方法,而不是到处写 Foo.SomeClass;您的 usingnamespace 也不会生成任何 "code"(在发出 IL 指令的意义上)。它所做的只是告诉编译器在您编写 SomeClass.

时将 Foo.SomeClass 放入 IL

以上是规范中定义的一组更细微的规则的简化,用于解析短格式类型名称;您可以阅读此内容了解更多详情:here and here

您希望在图表中强制执行依赖关系的级别是程序集引用级别:如果 Foo 项目从不引用 Bar 程序集,反之亦然,即使您尝试,代码也不会编译从一个程序集中引用另一个程序集中的类型。命名空间与此根本没有太大关系,因为同样,没有什么能阻止您在 Foo 命名空间中定义类型,而是在 Bar 程序集中定义类型。