命名空间

命名空间是一系列类型名称的领域。通常情况下,类型组织在分层的命名空间里,既避免了命名冲突又更容易查找。例如,处理公钥加密的RSA类型就定义在如下的命名空间下:

System.Security.Cryptography

命名空间组成了类型名的基本部分。下面代码调用了RSA类型的Create方法:

System.Security.Cryptography.RSA rsa=System.Security.Cryptography.RSA.Create();

命名空间是独立于程序集的。程序集是像.exe或者.dll一样的部署单元。命名空间并不影响成员的public、internal、private的可见性。

namespace关键字为其中的类型定义了命名空间。例如:

namespace outer.Middle .Inner

{
class classl { }

class Class2 { }

}

命名空间中的“.”表明了嵌套命名空间的层次结构。下面的代码在语义上和上一个例子是等价的:

namespace outer(
namespace Middle{
namespace Inner{
class Classl {}class Class2 {}}
})

类型可以用完全限定名称(fully qualified name),也就是包含从外到内的所有命名空间的名称,来指定。例如,上述例子中,可以使用Outer.Middle.Inner.Class1来指代Class1。

如果类型没有在任何命名空间中定义,则它存在于全局命名空间(global namespace)中。全局命名空间也包含了顶级命名空间,就像前面例子中的Outer命名空间。

1、using指令

using指令用于导入命名空间。这是避免使用完全限定名称来指代某种类型的快捷方法。以下例子导入了前一个例子的Outer.Middle.Inner命名空间:

using outer.Middle . Inner;class Test
{
static void Main ( ){
classl c;l/ Don't need fully qualified name}
}

在不同的命名空间定义相同名称的类型是完全合法的,这也是命名空间存在的最基本的意义。然而,假设开发者同时导入了这些命名空间,在引用同名类型时会收到来自编译器的错误,(这个问题可以用2.3.5小节的类型和命名空间别名解决)。

2、using static指令

从C#6开始,我们不仅可以导入命名空间还可以使用using static指令导入特定的类型。这样就可以直接使用类型静态成员而不需要指定类型的名称了。在接下来的例子中,我们这样调用Console类的静态方法WriteLine:

using static system.Console;class Test
{
static void Main(){ writeLine ( "Hello");})

using static指令将类型的可访问的静态成员,包括字段、属性以及嵌套类型(后续章节会讲解),全部导入进来。同时,该指令也支持导入枚举类型的成员(后续章节会讲解)。因此如果导入了以下的枚举类型:

using static System.Windows.Visibility;

我们就可以直接使用Hidden而不是Visibility.Hidden了:

var textBox = new TextBox { Visibility = Hidden }; // XAML- style

C#编译器还没有聪明到可以基于上下文来推断出正确的类型,因此在导入多个静态类型导致二义性时会发生编译错误。

3、命名空间中的规则

3.1、名称范围

外层命名空间中声明的名称能够直接在内层命名空间中使用。以下示例中的Class1在Inner中不需要限定名称:

namespace outer{
class Classl { }
namespace Inner{
class Class2 : classl{ }}
)

使用统一命名空间分层结构中不同分支的类型需要使用部分限定名称。在下面的例子中,SalesReport类继承Common.ReportBase:

namespace MyTradingcompany{
namespace C ommon
class ReportBase { }}
namespace ManagementReporting{
class salesReport : Common. PeportBase{ }}
}

3.2、名称隐藏

如果相同类型名称同时出现在内层和外层命名空间中,则内层类型优先。如果要使用外层命名空间中的类型,必须使用它的完全限定名称。

namespace outer
class Foo { }
namespace Inner{
class Foo { }
class Test{
Foo fl;
// - outer .Inner.Foo
outer.Foo f2;/l = outer.Foo
)
})

所有的类型名在编译时都会转换为完全限定名称。中间语言(IL)代码不包含非限定名称和部分限定名称。

3.3、重复的命名空间

只要命名空间内的类型名称不冲突就可以重复声明同一个命名空间:

namespace outer.Middle .Inner{
class Class1 {}}
namespace outer. Middle . Inner{
class class2 {}

上述例子也可以分为两个不同的源文件,并将每一个类都编译到不同的程序集中(这个用处很大)。

3.4、嵌套的using指令

我们能够在命名空间中嵌套使用using指令,这样可以控制using指令在命名空间声明中的作用范围。在以下例子中,Class1在一个命名空间中可见,但是在另一个命名空间中不可见:

name space N1{
class Classl { }}
namespace N2

{
using Nl;
class class2 : class1 { }

}
namespace N2
{
class Class3 : class1 {}l /compile-time error
 }

3.5、类型和命名空间别名

导入命名空间可能导致类型名称的冲突,因此可以只导入需要的特定类型而不是整个命名空间,并给它们创建别名。例如:

using PropertyInfo2 = system.Reflection.PropertyInfo;class Program{ PropertyInfo2 p; }
下面代码为整个命名空间创建别名:

using R = system.Reflection;
class Program { R.PropertyInfo p; }

编程是个人爱好