TOC

This article is currently in the process of being translated into Chinese (~96% done).

类 :

Namespaces

本教程最开始的某个章节简单讨论过名空间。你可能已经知道这个关键字(namespace),因为在大多数包含C#代码的文件里都有它,通常出现在文件开头。一个名空间(namespace)其实就是把一批如类等的类型归类到一个针对这批类型专门命名的一个空间里面的一种方法。当Visual Studio新建一个项目时,也生成了一个默认的名空间,并在此空间里面放入了项目的第一个文件(最少对于命令行应用的项目类型是这样的)。如下述代码所示:

using System;  

namespace MyProject  
{  
    class Program  
    {  
static void Main(string[] args)  
{  
// More code below this....

上述代码中,名空间“MyProject”就是应用程序的一部分,如果要在此应用的外部使用其内部的类,就需要在类名称前面加上名空间名称。在使用深藏于.NET framework里面的东西时,这也是一样的,就象这样:

System.IO.File.ReadAllText("test.txt");

这里,代码使用了System.IO名空间(namespace包含的File类ReadAllText()方法。当然,每次使用某名空间里面的一个类都要写这么长的一串名称是很无聊,因此C#允许使用using声明一次性“引入”一整个名空间到当前文件的作用域。同样,这种情况也是很常见的,因为这通常都会出现在大多数C#文件的开头。比如上面的例子,如果需要多次使用File类,就应该使用using声明引入System.IO名空间,象这样:

using System;
using System.IO;
// More using statements here...

为什么会需要名空间?

对编程的初学者来说,可能不理解为什么会需要名空间。为什么不直接把所有的类全部都放在同一个名空间里面,那不就都能直接引用了?是这样没错,但只是对很小的项目来说。一旦类的数量开始变得越来越多,把它们归类到不同的名空间里面就很有用了。这显然让查找代码变得更方便了,尤其是当把代码文件保存到与名空间名称相应的文件夹里时 - 实际上,如果在项目中增加一个文件夹,然后在里面新增类,Visual Studio会自动把这个类放入到相应的名空间里面。因此如果在MyProject项目中增加一个MyFolder文件夹,则在此文件夹内新增的类默认都会被放到MyProject.MyFolder名空间里面。

.Net framework本身就是名空间存在必要性的一个很强的例子。想想如果此构架下所有的类都平级地存在于一个全局的名空间里面 - 那是一个乱!反之,这些类组织得很好,以System作为大多数类的顶级名空间,然后是诸如用于输入/输出事务的System.IO,与网络事务相关的System.Net,及与邮件事务相关的System.Net.Mail等次级名空间。

名称冲突与名空间

由前面的讨论可知,名空间还起到了对类型(通常是都类)进行封装的作用,让类型只存在于自身的作用域。这也表示完全可以建立与同一个项目其它地方,甚至是.NET framework内部的类型名称同名的类。比如需要建立一个自己的File类。从前面的例子中已知,在System.IO名空间中已经有一个这样的类了,但是这完全不影响在自己的名空间里面再建一个File类,象这样:

using System;  

namespace MyProject.IO  
{  
    class File  
    {  
public static void HelloWorld()  
{  
    Console.WriteLine("Hello, world!");  
}  
    }  
}

然后在使用这个类的时候,比如,在Program.cs代码的Main方法(假设是个命令行程序)中调用,即可以使用类的全名称调用:

MyProject.IO.File.HelloWorld();

也可以先使用using声明引入名空间,就象引入其它(系统的或是用户定义的)名空间一样。下面是更完整的例子:

using System;
using MyProject.IO;

namespace MyProject
{
    class Program
    {
static void Main(string[] args)
{
    File.HelloWorld();
}
    }
}

到目前为止,一切还好!不过,如果同时也要用System.IO名空间里面的File类怎么办呢?确实,这就是冲突的地方,因为如果用using声明把这个名空间也引入了,编译器就没法知道你引用的是那个File类了 - 是自己定义的那个,还是来自System.IO名空间里面的那个。一个解决方案是,只引入其中的一个名空间(最好是被引用的类型数量最多的那个),然后使用类的全名称来引用来自另一个名空间里面的同名类,象下面例子一样:

using System;
using System.IO;

namespace MyProject
{
    class Program
    {
static void Main(string[] args)
{
    MyProject.IO.File.HelloWorld();
}
    }
}

不过每次都要打入这么一长串还是有点麻烦,特别是当类处于名空间层级的非常深处时,比如,MyProject.FileStuff.IO.File。好在,C#有办法解决。

使用别名指示

为大幅缩短名空间名称,可以用别名指示使用另一个名称来引入名空间。注意下例中的实现方式:

using System;
using System.IO;
using MyIO = MyProject.IO;

namespace MyProject
{
    class Program
    {
static void Main(string[] args)
{
    File.ReadAllText("test.txt");
    MyIO.File.HelloWorld();
}
    }
}

关键在第三行,引入了MyProject.IO名空间,并给了它一个很短的名称(MyIO),之后如果要引用此名空间中的类型,就可以使用此短名称了。此例中其实并没有真正减少多少长度,不过设想下更长的名称及更多的名空间层级,真的会变得很长,很多层。

总结

名空间的概念提供了使用命名的空间对类型进行封装的机会,从而增强了代码结构,并使得建立多个同名的类型可行,只要把它们放到不同的名空间内即可。


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!