C# 命名空间是否被编译成 IL 文件以成为 "complete" 名称?

Is C# namespace compiled into IL files to be "complete" names?

例如,如果我有

namespace a
    namespace b
{
    class C...
    class D...
}

那么编译后,在IL文件中,命名空间信息在哪里?我是否得到两个名为 a.b.C 和 a.b.D 的 classes,其中 class 名称以命名空间名称为前缀?

或者我在程序集文件中得到一个命名空间 a.b 并在其中包含 class C/class D,就像 C# 代码一样?

CLR 对命名空间一无所知。当你访问一个类型时,CLR 需要知道类型的全名和 哪个程序集包含类型的定义,以便运行时可以加载正确的程序集, 找到类型,并对其进行操作。

这意味着你的 class Cnamespace b 中的存储方式类似于 b.C

IL 中不存在命名空间。它们不作为元数据保存。在 IL 中,所有对类型和方法的引用都必须使用完全限定名称。

然而,IL 识别并明确允许类型名称包含点。 C# 或 VB.NET 命名空间是一种构建于其之上的语言构造:它们本质上是一种机制,允许您仅指定类型名称的后面以点分隔的部分。 using 或命名空间 Imports 指令是提示编译器猜测不完整类型名称的前部分;但在所有情况下,编译器都必须将非完全限定名称 (SomeType) 转换为完全限定类型名称 (SomeNamespace.SomeType)。

让我们先把事情弄清楚。

  • IL 基本上就是 .NET
  • 中使用的 'basic building block' 语言
  • 一个 DLL 包含 IL 和元数据

如果您启动 ildasm(从 visual studio 命令提示符),将您的 DLL 放在那里,转储所有内容,然后在您喜欢的文本编辑器中浏览它,您就可以看到两者。这将包含元数据和 IL 代码。

IL 不包含名称空间信息,它只是由 'tokens' 组成,它们基本上是 类 的 ID、函数等。这些 ID 可以解析。

DLL 中的一个东西是命名空间的元数据容器。或者正如 ILDASM 将向您展示的那样:

// ================================= M E T A I N F O ================================

// ===========================================================
// ScopeName : MyNamespace
// MVID      : {22EE923F-126A-43BA-8A72-59A7A069625A}
// ===========================================================
// Global functions
// -------------------------------------------------------
// 
// Global fields
// -------------------------------------------------------
// 
// Global MemberRefs
// -------------------------------------------------------
// 
// TypeDef #1 (02000002)
// -------------------------------------------------------
//  TypDefName: MyNamespace.MyType  (02000002)
//  Flags     : [Public] [AutoLayout] [Class] [AnsiClass]  (00000001)
//  Extends   : 01000001 [TypeRef] System.Object
//  Field #1 (04000001)

现在,您所谓的命名空间基本上是以相同 'dot' 前缀开头的 typedefs 元数据标记的集合。名称空间并不是真正的 'entity',这意味着它本身没有标记。命名空间仅存在,因为存在包含点(确实具有标记)的类型的名称。换句话说,名称空间并不直接存在;它源自那里的类型。

现在,知道了这一点,您的问题就很容易得到解答了:

So after compiling, in IL file, where's the namespace information? Do I get two classes named a.b.C and a.b.D where the class names is prefixed by the namespace name?

是的,没有它们,命名空间将不存在。

另外两个回复写了点东西,我只好写反了:-)

假设微软在两个阵营中都站稳脚跟...阅读 ECMA-335:

第 114 页

While some programming languages introduce the concept of a namespace, the only support in the CLI for this concept is as a metadata encoding technique. Type names are always specified by their full name relative to the assembly in which they are defined.

但是即使这个 ECMA 标准也自由地使用命名空间概念:

In order to prevent name collisions into the future, all custom attributes in the System namespace are reserved for standardization.

并且IL语言支持.namespace指令,相当于C#的命名空间指令(这条指令在ECMA标准中有命名,但是没有例子。ILASM正确编译了这个例子和反编译代码是人们所期望的)...

.namespace A
{
    .namespace B
    {
        .class public auto ansi beforefieldinit C
            extends [mscorlib]System.Object
        {
            // Nested Types
            .class nested public auto ansi beforefieldinit D
                extends [mscorlib]System.Object
            {
                // Methods
                .method public hidebysig specialname rtspecialname 
                    instance void .ctor () cil managed 
                {
                    // Method begins at RVA 0x2050
                    // Code size 7 (0x7)
                    .maxstack 8

                    IL_0000: ldarg.0
                    IL_0001: call instance void [mscorlib]System.Object::.ctor()
                    IL_0006: ret
                } // end of method D::.ctor

            } // end of class D


            // Methods
            .method public hidebysig specialname rtspecialname 
                instance void .ctor () cil managed 
            {
                // Method begins at RVA 0x2050
                // Code size 7 (0x7)
                .maxstack 8

                IL_0000: ldarg.0
                IL_0001: call instance void [mscorlib]System.Object::.ctor()
                IL_0006: ret
            } // end of method C::.ctor

        } // end of class A.B.C
    }
}

但注意生成的代码相当于不使用.namespace直接在.class中包含全名:

.class public auto ansi beforefieldinit A.B.C
    extends [mscorlib]System.Object
{
    // Nested Types
    .class nested public auto ansi beforefieldinit D
        extends [mscorlib]System.Object
    {
        // Methods
        .method public hidebysig specialname rtspecialname 
            instance void .ctor () cil managed 
        {
            // Method begins at RVA 0x2050
            // Code size 7 (0x7)
            .maxstack 8

            IL_0000: ldarg.0
            IL_0001: call instance void [mscorlib]System.Object::.ctor()
            IL_0006: ret
        } // end of method D::.ctor

    } // end of class D


    // Methods
    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [mscorlib]System.Object::.ctor()
        IL_0006: ret
    } // end of method C::.ctor

} // end of class A.B.C

然后 Type class 有一个 Name 和一个 Namespace 属性。 Type class(作为 mscorlib 的一大块)是 CLR 良好工作不可或缺的一部分。

所以如果问题是:编译的 .NET 程序中是否有显式命名空间?响应是 "no"。只有全名。

如果问题是:.NET 中有命名空间的概念吗(any/all 级别)?响应是 "yes"。它存在于 IL(源代码级别,.namespace)、CLR(.NET API、Type.Namespace)、C#(.NET 的 "main" 语言,用于编写几乎所有的 .NET 库)(namespace).