C# 命名空间是否编译为 IL 文件以“完整”名称
本文关键字:完整 名称 文件 IL 命名空间 是否 编译 | 更新日期: 2023-09-27 17:55:28
例如,如果我有
namespace a
namespace b
{
class C...
class D...
}
那么编译后,在IL文件中,命名空间信息在哪里?我是否得到两个名为 a.b.C 和 a.b.D 的类,其中类名以命名空间名称为前缀?
或者我在程序集文件中得到一个命名空间 a.b,里面有类 C/类 D,就像 C# 代码一样?
CLR 对命名空间一无所知。访问类型时,CLR需要知道类型的全名和哪个程序集包含类型的定义,以便运行时可以加载正确的程序集,找到类型,并对其进行操作。
这意味着您在namespace b
中的class C
存储得像b.C
.
另外两个回复写了一些东西,所以我必须写相反的:-)
假设Microsoft在两个阵营中都保持了脚步......阅读 ECMA-335:
114 页
虽然某些编程语言引入了命名空间的概念,但 CLI 中唯一的支持 因为这个概念是一种元数据编码技术。类型名称始终由其完整名称指定 相对于在其中定义它们的程序集的名称。
但即使是这个 ECMA 标准也可以自由地使用命名空间概念:
为了防止将来发生名称冲突,System 命名空间中的所有自定义属性都保留用于标准化。
并且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
类具有Name
和Namespace
属性。Type
类(作为 mscorlib 的一大块)是 CLR 良好工作不可或缺的一部分。
因此,如果问题是:编译的 .NET 程序中是否有显式命名空间?回答是"否"。只有全名。
如果问题是:.NET 中是否存在命名空间的概念(在任何/所有级别)?回答是"是"。它存在于IL(源代码级别,.namespace
),CLR(.NET API,Type.Namespace
),C#(.NET的"主要"语言,用于编写几乎所有的.NET库)(namespace
)。
IL 中不存在命名空间。它们不会保留为元数据。在 IL 中,对类型和方法的所有引用都必须使用完全限定的名称进行。
但是,IL 识别并显式允许类型名称包含点。C# 或 VB.NET 命名空间是在此基础上构建的语言构造:它们本质上是一种机制,允许您仅指定类型名称的后面以点分隔的部分。 using
或命名空间Imports
指令是编译器猜测不完整类型名称的前一部分的提示;但是在所有情况下,编译器都必须将非完全限定名(SomeType
)转换为完全限定的类型名(SomeNamespace.SomeType
)。
让我们先直截了当地说点。
- IL基本上只是.NET中使用的"基本构建块"语言
- DLL 包含 IL 和元数据
如果您启动ildasm
(从 Visual Studio 命令提示符),将 DLL 放在那里,转储所有内容,然后在您喜欢的文本编辑器中浏览它,您可以看到两者。这将包含元数据和 IL 代码。
IL 不包含命名空间信息,它只是由"令牌"组成,这些令牌基本上是类、函数等的 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)
现在,您基本上称为命名空间的是以相同的"点"前缀开头的 typedefs 元数据令牌的集合。命名空间并不是真正的"实体",这意味着它本身没有令牌。命名空间之所以存在,是因为存在包含点(具有标记)的类型名称。换句话说,命名空间不直接存在;它派生自那里的类型。
现在,知道了这一点,您的问题可以很容易地回答:
那么编译后,在IL文件中,命名空间信息在哪里?做 我得到两个名为 a.b.C 和 a.b.D 的类,其中类名是 以命名空间名称为前缀?
是的,没有它们,命名空间就不会存在。