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 C
在 namespace 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
).
例如,如果我有
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 C
在 namespace 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
).