将C#名称空间编译成IL文件是否为“完整”名称?

时间:2015-06-12 07:17:37

标签: c# namespaces il

例如,如果我有

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

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

或者我在汇编文件中得到一个命名空间a.b,里面有C / D类,就像C#代码一样?

4 个答案:

答案 0 :(得分:5)

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

这意味着class Cnamespace b的存储方式与b.C一样。

答案 1 :(得分:3)

其他两个回答写了一些东西,所以我必须写相反的东西: - )

让我们说微软一直在两个阵营中徘徊......阅读ECMA-335

第114页

  

虽然一些编程语言引入了命名空间的概念,但是CLI中唯一的支持   这个概念是作为元数据编码技术。类型名称始终由其完整指定   相对于定义它们的程序集的名称。

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

  

为了防止将来发生名称冲突,系统命名空间中的所有自定义属性都保留用于标准化。

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类具有NameNamespace属性。而Type类(作为mscorlib的一大块)对于CLR的良好工作是不可或缺的。

因此,如果问题是:编译的.NET程序中是否有明确的命名空间?答案是" no"。只有全名。

如果问题是:.NET中是否存在命名空间的概念(在任何/所有级别)?答案是"是"。它存在于IL(源代码级别,.namespace),CLR(.NET API,Type.Namespace),C#("主要" .NET语言,用于编写)中几乎所有的.NET库)(namespace)。

答案 2 :(得分:1)

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

然而,

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

答案 3 :(得分:1)

让我们先做点准备。

  • IL基本上只是“基本构建块”' .NET中使用的语言
  • DLL包含IL和元数据

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

IL不包含命名空间信息,它只是由“令牌”组成,它们基本上是类,功能等的ID。这些ID' s可以解决。

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)

现在,你基本上称之为命名空间的是typedef元数据标记的集合,它们以相同的'点'开头。字首。命名空间实际上并不是一个“实体”,这意味着它本身没有令牌。仅存在命名空间,因为存在包含点(具有令牌)的类型的名称。换句话说,命名空间并不直接存在;它来自那里的类型。

现在,知道这一点,你的问题很容易回答:

  

编译后,在IL文件中,命名空间信息在哪里?做   我得到两个名为a.b.C和a.b.D的类,其中类名是   以命名空间名称?

为前缀

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