【问题标题】:What C# compiles when using namespaces使用命名空间时 C# 编译的内容
【发布时间】:2020-05-27 19:07:32
【问题描述】:

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

我希望维恩图作为可视化得到赞赏:

然而,FooBar 之间的一个类从裂缝中溜走了,尽管强制执行,但有人在 Foo 中引用了一个来自 Bar 的类。

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

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

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

【问题讨论】:

  • 您将代码编译成程序集,而不是命名空间。如果这些程序集包含对其他程序集的引用,它们本身不会改变。这是一个参考,而不是参考代码的副本。
  • 您是如何尝试执行此操作的?
  • 在人际层面而非技术层面强制执行。

标签: c# compilation namespaces


【解决方案1】:

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

程序集中已编译的 IL 代码通过其完全限定名称来引用类型:Foo.SomeClass 而不是 SomeClassBar.OtherClass 而不是 OtherClass,等等。编译器的工作是找出 哪个 完全限定类型名称,当您编写缩短形式 SomeClass 时,您真正的意思是——因为您可以在命名空间 Foo 中定义一个名为 SomeClass 的类,Bar,甚至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; 时,没有任何东西被“导入”,它只是提供了一个方便的替代方式,而不是在任何地方写 Foo.SomeClass;您的usings 或namespaces 也不会生成任何“代码”(在发出 IL 指令的意义上)。它所做的只是告诉编译器在您编写SomeClass 时将Foo.SomeClass 放入IL 中。

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

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

【讨论】:

  • 是的,这很有意义。值得一提的是,对于其中一个应用程序,我们使用的是 Unity3D。所以编译有点超出我们的控制范围。这可能正是我一开始担心的原因......
猜你喜欢
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多