命名空间(namespace)用于对相关的类型进行逻辑性的分组,使用命名空间可以方便的定位一个类型。对于编译器来说,命名空间的作用就是为一个类型的名称附加一些以句点分隔的符号,从而使名称变得更长,更可能具有唯一性。
例如,构造一个List<string>的对象:
显然,像上面那种写法非常繁锁,每次使用一个类型都要写上长长一串命名空间,幸好,编译器已经提供了一种机制来简化我们的代码,C#编译器通过using命令来提供这个机制。using指令指示编译器尝试为一个类型附加不同的前缀,直到找到一个匹配项。using指令是完全可选的,如果愿意,完全可以输入一个类型的完全限定名称。以下代码和上面的效果完全一致:
using System.Collections.Generic; //尝试附加 System.Collections.Generic. 前缀
using System.Text; //尝试附加 System.Text. 前缀
public class Program
{
static void Main(string[] args)
{
List<string> MyList = new List<string>();
}
}
在前面的代码中,编译器需要保证引用的每个类型都确实存在,而且代码以正确的方式使用那个类型--也就是调用确实存在的方法,向这些方法传递正确数量的实参,保证实参具有正确的类型,正确使用方法的返回值,等等。如果编译器在程序集中找不到具有指定名称的一个类型,就会在类型名之前附加System. 前缀,并核实这样生成的名称与一个现有的类型匹配。如果仍找不到匹配项,就继续为类型名称附加System.Collections.Generic. 前缀,直到找到匹配项为止。
如果有两个(或更多)类型在不同的命名空间中具有相同的名称,编译器会报一个错误消息说类型的引用不明确。Microsoft强烈建议开发人员为类型定义具有唯一性的名称,但有时候,非不为也,是不能也。 例如你当前开发的系统要同时与A公司的系统和B公司的系统集成,而这两个公司都定义了一个ProductOperation的类,而这两个类做的是完全不同的两件事情,在这种情况下,由于无法干预类型的命名,所以在引用这两个类型时,可以使用各自的完全限定名称来加以区分。
新建一个类ProductOperation,命名空间为CompanyA.Product :
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CompanyA.Product
{
public class ProductOperation
{
public ProductOperation()
{ }
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CompanyB.Product
{
public class ProductOperation
{
public ProductOperation()
{ }
}
}
using System.Collections.Generic;
using System.Text;
using CompanyA.Product; //尝试附加 CompanyA.Product. 前缀
using CompanyB.Product; //尝试附加 CompanyB.Product. 前缀
namespace Test
{
class Program
{
static void Main(string[] args)
{
ProductOperation operation = new ProductOperation();
}
}
}
运行上面的代码会出现不明确的引用的错误,如图:
这是因为当编译器尝试在ProductOperation前面加前缀的时候,发现CompanyA.Product和CompanyB.Product命名空间中都有ProductOperation类,它不知道该引用哪一个,导致了引用不明确的错误,为了消除歧义,必须显示的告诉编译器创建的是哪一个命名空间中的ProductOperation.
using System.Collections.Generic;
using System.Text;
using CompanyA.Product; //尝试附加 CompanyA.Product. 前缀
using CompanyB.Product; //尝试附加 CompanyB.Product. 前缀
namespace Test
{
class Program
{
static void Main(string[] args)
{
//现在没错误了
CompanyA.Product.ProductOperation operation = new CompanyA.Product.ProductOperation();
}
}
}
using命令还支持另一种形式,允许为一个类型或命名空间创建别名。如果只想用一个命名空间中的少数几个类型,不希望它的所有类型都跑出来“污染”全局命名空间,别名就显得十分方便了。以下代码演示了如何用using创建别名的方式解决前面歧义性的问题:
using System.Collections.Generic;
using System.Text;
using CompanyA.Product;
using CompanyB.Product;
//将 ProductA 定义为 CompanyA.Product.ProductOperation 的别名
using ProductA = CompanyA.Product.ProductOperation;
namespace Test
{
class Program
{
static void Main(string[] args)
{
ProductA operation = new ProductA();
}
}
}
命名空间和程序集(实现了一个类型的文件)不一定是相关的。同一个命名空间中的各个类型可能是在不同的程序集中实现的。例如:System.IO.FileStream 类型是在MSCorLib.dll程序集中实现的,而System.IO.FileSystemWatcher是在System.dll程序集中实现的。事实上.NET Framework根本没有一个System.IO的程序集。在一个程序集中,也可能包含不同命名空间中的类型。例如,System.Int32和System.Test.StringBuilder类型都在MSCorLib.dll程序集中。