关于C#中的命名空间

来源:互联网 发布:java ssh三层架构 编辑:程序博客网 时间:2024/05/17 09:29

 

命名空间
 
命名空间是程序之中控制名称的可见度的一种机制。利用命名空间可以使标识符之间的命名冲突降到最低,这么一来,“不同来源的程序组件”的协同工作就变得比较容易。在介绍命名空间机制之前,我们最好先弄清楚命名空间所要解决的问题。
所有“未被置入某个命名空间的名称,都会被自动置入一个独一无二的“无名全局声明空间”内。这些名称在程序内从头到尾都能被看见峭论它们出现在相同的程序文件或不同的程序文件内。全局声明空间中的每个名称都必须独一无二,这么一来程序才能被成功地生成出来。全局名称会给“将某些独立组件合并到我们的程序中”带来相当难度。
举个例子,想象你开发一个二维图形组件,并把一个global class 命名为Point。你使用你的组件,一切正常,于是你向一些朋友谈起它,他们自然也想试试看。在此同时,我开发了一个三维图形组件,这回轮到我把我的一个global class 命名为Point。我用我的组件,也一切正常。我向朋友展示它,朋友们表示出极大的兴趣,也想试试这个组件。到目前为止,每个人都很开心--至少对于我们的项目是如此。
现在假设你我有一个共同的朋友,正在编写一个2D/3D的游戏引擎,他愿意利用你我这两个“受到高度表扬”的组件,不幸的是兴妖作怪在程序中加入这两个组件时,两个原本独立的标识符Point导致其游戏引擎编译失败。由于这两个组件不是他写的,修正这两个组件使协同工作并不是太轻松的事情。
 
命名空间(namespace)给“全局名称冲突问题”提供一个通解,所谓命名空间,就是取一个名称,并在这个名称内封装我们所定义的classes和其他types。也就是说,置于某个命名空间内的“名称”,在程序中一般是不可见的,因此我们说,一个命名空间代表一个独立的声明空间或生存空间。
现在将各人的Point class定义于各自的命名空间中:
 
namespace DisneyAnimation_2DGraphics
{
   Public class Point
{………}
}
namespace DisneyAnimation_3DGraphics
{
   Public class Point
{………}
}
命名空间的定义由关键字namespace引导,紧跟在关键字后面的是这个命名空间独一无二的标识符。如果我们用已经存在的命名空间标识符来作为新命名空间的,编译器会认为我们想在原先存在的命名空间内加入新声明。两个名称相同的命名空间并不会导致冲突。因此,我们可以把命名空间的声明分散到不同的程序文件中去。
命名空间的内容被封在一对“{ }”之间。我们的两个Point classes对整个程序来说不再是可见的,它们分别嵌套定义于各自的命名空间。我们说每个class是其命名空间内的一个成员。
Using指令在这种情况下就显得有点画蛇添足了,一旦我们的那位朋友在他的程序中同时“开启”(曝光)两个命名空间。
 using DisneyAnimation_2DGraphics;
 using DreamWorksAnimation_3DGraphics;
那么,使用无修饰标识符Point仍会导致编译错误。为了明确指出是这个或那个Point class,我们必须运用全饰名称,像这样:
 DreamWorksAnimation_3DGraphicsPoint origin;
由右向左读这句话,意思就是声明一个名为originobject,其类型为Point,定义于命名空间DreamWorksAnimation_3DGraphics内。
然而一旦发生跨命名空间的名称冲突,事情就不再那么简单。若我们“开启”两个独立的命名空间,每个命名空间内都用上了同一个标识符,就像前面的Point一样。这时如果再运用被多重定义的标识符Point,就会发生错误。编译器不会试图区分两个标识符的优先次序,或试图消除其所代表的object的混淆现象。一个解决办法是,像我们以前所做的那样,明确指出每个标识符的访问路径,另一个办法是,为一个或所有多重定义的实体取一个别名,也就是说,运用下面这种形式的using指令:
 namespace  GameApp
 {
    //exposes the two instances of Point
     using DisneyAnimation_2DGraphics;
     using DreamWorksAnimation_3DGraphics;
 
 //OK:create unique identifiers for each instance
   using  Point2D = DisneyAnimation_2DGraphics.Point;
   using Point3D = DreamWorksAnimation_3DGraphics.Point;
  
   class myClass
{
 Point2D  thisPoint;
 Point3D thatPoint;
}
}
 
别名仅在当前的声明空间内有效,也就是说,所谓的“别名”并不会给这个class带来另一个永久有效的型别名称。如果我们试图跨越命名空间来使用这个别名,如:
namespace  GameEngine
{
 class App
   {
           //error:not recognized
           Private GameApp.Point2D origin;
     
}
}
编译器会不知所措,因而发出如下信息:
The type or namespace name ‘Point2D’ does not exist in the class or namespace ‘GameApp’
使用命名空间时,我们并不知道其中已经定义了多少标识符,程序每多开启一个命名空间,就多增加发生混乱的可能性,我们得重新编译,看看有没有爆发灾难。因此,C#语言尽量使“开启命名空间所造成的程序混乱”的可能性降到最低。如果多个using指令使得“某个标识符所代表的两个或多个实体”在当前的声明空间中变得可见了,就像先前两个Point classes那样,那么,只有“直接使用未经资格修饰(unqualified)的标识符才会发生错误。如果我们不适用那个标识符,歧义的状况会潜伏并保持下去,编译器不会给出任何错误或警告。
如果“通过using指令而曝光的标识符”和“我们所定义的标识符”重复,那么我们所定义的那个标识符拥有优先权。一个未经资格修饰的标识符问题被编译器为我们自己定义的那个实体,可以说,我们定义的那个实体屏蔽了命名空间内的那个同名标识符,程序将会完全依照“添加命名空间前”的方式运行。
命名空间该有怎么样的名称?诸如DrawingDataMath之类的一般性名称,其保持唯一个可能性很小。一般推荐的策略是在名称中使用“足以代表你的组织或项目”的前缀字。
命名空间是组件开发的必备要素。正如我们所看到的,有了它,其他程序都会较容易地重复利用我们的软件。