名称空间
在继续学习前,应花一定的时间了解一个比较重要的主题—名称空间。它们是 .NET 中提供应用程序代码容器的方式,这样就可以唯一地标识代码及其内容。名称空间也用作 .NET Framework 中给项分类的一种方式。大多数项都是类型定义,例如,本章描述的简单类型(System.Int32
等)。
默认情况下,C#代码包含在全局名称空间中,这意味着对于包含在这段代码中的项,全局名称空间中的其他代码只要通过名称进行引用,就可以访问它们。可使用 namespace
关键字为花括号中的代码块显式定义名称空间。如果在该名称空间代码的外部使用名称空间中的名称,就必须写出该名称空间中的限定名称。
限定名称包括它所有的分层信息。这意味着,如果一个名称空间中的代码需要使用在另一个名称空间中定义的名称,就必须包括对该名称空间的引用。限定名称在不同的名称空间级别之间使用句点字符( .
)。如下所示:
namespace LevelOne
{
// code in LevelOne namespace
// name "NameOne" defined
}
// code in global namespace
这段代码定义了一个名称空间 LevelOne
,以及该名称空间中的一个名称 NameOne
(注意这里在应该定义名称空间的地方添加了一个注释,而没有列出实际代码,这是为了使我们的讨论更具普遍性)。在名称空间 LevelOne
中编写的代码可以直接使用 NameOne
来引用该名称,但全局名称空间中的代码必须使用限定名称 LevelOne.NameOne
来引用这个名称。
根据约定,名称空间通常采用 PascalCase 命名方式。
在名称空间中,使用关键字 namespace
还可以定义嵌套的名称空间。嵌套的名称空间通过其层次结构来引用,并使用句点为层级结构分层。这最好通过一个示例来加以说明。考虑下面的名称空间:
namespace LeveOne
{
// code in LevelOne namespace
namespace LevelTwo
{
// code in LevelOne.LevelTwo namespace
// name "NameTwo" defined
}
}
// code in global namespace
在全局名称空间中,NameTwo
必须引用为 LevelOne.LevelTwo.NameTwo
; 在 LevelOne
名称空间中,可以引用为 LevelTwo.NameTwo
; 在LevelOne.LevelTwo
名称空间中,可以引用为 NameTwo
。
非常重要的一点是,名称是由名称空间唯一定义的。可在 LevelOne
和 LevelTwo
名称空间中都定义名称 NameThree
:
namespace LevelOne
{
// name "NameThree" defined
namespace LevelTwo
{
// name "NameThree" defined
}
}
这定义了两个不同的名称 LevelOne.NameThree
和 LevelOne.LevelTwo.NameThree
,可以独立使用它们,互补干扰。
创建名称空间后,即可使用 using
语句简化对它们所含名称的访问。实际上,using
语句的意思是“我们需要这个名称空间中的名称,所以不要每次总是要求使用限定名称”。例如,在下面的代码中,LevelOne
名称空间中的代码可以直接访问 LevelOne.LevelTwo
名称空间中的名称,而不必使用限定名称:
namespace LevelOne
{
using LevelTwo;
namespace LevelTwo
{
// name "NameTwo" defined
}
}
LevelOne
名称空间中的代码现在可以直接使用 NameTwo
引用 LevelTwo.NameTwo
。
有时,与上面的 NameThree
示例一样,不同名称空间中的相同名称会产生冲突(此时,代码无法编译,编译器会告诉我们名称有冲突)。此时,可使用 using
语句为名称空间提供一个别名。
namespace LevelOne
{
using LT = LevelTwo;
// name "NameThree" defined
namespace LevelTwo
{
// name "NameThree" defined
}
}
LevelOne
名称空间中代码可以把 LevelOne.NameThree
引用为 NameThree
,把 LevelOne.LevelTwo.NameThree
引用为 LT.NameThree
。
using
语句引用到包含它们的名称空间,以及该名称空间中包含的嵌套名称空间。在上面的代码中,全局名称空间不能使用 LT.NameThree
。但如果 using
语句声明如下:
using LT = LevelOne.LevelTwo;
namesapce LevelOne
{
// name "NameThree" defined
namespace LevelTwo
{
// name "NameThree" defined
}
}
&emsp然后,全局名称空间中的代码和 LevelOne
名称空间中的代码就可以使用 LT.NameThree
。
需要注意 ⚠️ 特别重要的一点:using
语句本身不能访问另一个名称空间中的名称。除非名称空间中的代码以某种方式链接到项目上,或者代码是在该项目的源文件中定义的,或者是在链接到该项目的其他代码中定义的,否则就不能访问其中包含的名称。另外,如果包含名称空间的代码链接到项目上,那么无论是否使用 using
,都可以访问其中包含的名称。using
语句便于我们访问这些名称,减少代码量,以及提高可读性。
回头分析本章开头的 HelloWorld 中的代码,会看到下面这些被应用到名称空间上的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
...
}
以 using
关键字开头的5行代码声明在这段C#代码中使用 System
、System.Collections.Generic
、System.Linq
、System.Text
和 System.Threading.Tasks
名称空间,它们可以在该文件的所有名称空间中访问,不必进行限定。System 名称空间是 .NET Framework 应用程序的根名称空间,包含控制台应用程序需要的所有功能。其他4个名称空间常用于控制台应用程序,所以该程序包含了它们。
最后,为应用程序代码本身声明一个名称空间 HelloWorld
。