Show/Hide Toolbars

XSharp

 

命名空间是项目名称的前缀,它提供了类型和其他 .Net 元素的逻辑分组,使具有共同目的的项目更容易结构化,并避免命名冲突。由于 .Net 中有大量的库和类(在系统库和第三方库中,以及在每个用 .Net 编写的应用程序中),如果不使用命名空间而使用简单的小名,就会导致大量的命名冲突,从而无法区分彼此。例如,在 Windows 窗体系统库中有一个名为 “Button”(代表按钮控件)的类型,在 WPF 中也有一个,在 VOSDK GUI 类中也有一个,当然新的类型化 VOSDK GUI 类库也有一个。此外,其他几十个自定义控件库也很可能包含相同的命名类型!为了将它们区分开来,每个版本的类型都添加了一个额外的前缀名称(命名空间):

 

System.Windows.Forms.Button // Windows forms

System.Windows.Controls.Button  // WPF

VO.Button // VOGUI library

XSharp.VO.Button // Typed SDK GUI library

 

对于完整的类名 System.Windows.Forms.Button,最后一个点(System.Windows.Forms)之前的所有内容都称为类的命名空间,而其余部分则称为简短的类名。请注意,命名空间并不是具体的东西,它在 .Net 汇编中并不作为一个单独的实体存在,它只是对所有类名使用描述性名称前缀的一种约定,并不是强制性的。使用点作为名称分隔符也是.Net 中的一种约定俗成的做法,如果选择其他字符(如下划线)也可以达到同样的目的,这样 winforms 类的名称就变成了 System_Windows_Forms_Button,其中 “System_Windows_Forms” 就是名称中的命名空间部分。

 

另外,按照惯例,命名空间和类型名称通常采用以下格式:

<公司名>.<库名>.<可选的其他分组名>.<简短的类型名称>

XSharp.VO.Button(XSharp.VO.Button)就是这样命名的,其中 “XSharp” 是公司名称,“VO” 代表程序库,而 “Button” 则是实际的类(简称)名称。可选的附加组名称可进一步改善类型名称的结构,通常用于大型库中,在这种情况下,将大量可用项目进行逻辑分组非常重要。

为类型名称指定命名空间

在 X# 中,有几种方法可以为代码中定义的类型/类提供命名空间。最常见的方法是使用 BEGIN...END NAMESPACE 块语句:

BEGIN NAMESPACE OurCompany.CommonLibrary
  CLASS GeneralUseType
  // ...
  END CLASS
END NAMESPACE

在代码块中定义的每一个类型,编译器都会自动在其名称前加上所提供的命名空间,因此上述示例中的类将变成 OurCompany.CommonLibrary.GeneralUseType。此外,BEGIN NAMESPACE 块还可以嵌套(任意级别),上面的代码也可以这样写:

BEGIN NAMESPACE OurCompany
  BEGIN NAMESPACE CommonLibrary
    CLASS GeneralUseType
    // ...
    END CLASS
  END NAMESPACE
END NAMESPACE

另一种方法是直接在类声明中提供名称的命名空间部分:

CLASS OurCompany.CommonLibrary.GeneralUseType
// ...
END CLASS

最后,还可以在项目属性中定义默认名称空间(与 -ns 编译器选项相对应)。定义后,代码中所有未明确分配命名空间的类名都会自动获得项目选项中提供的命名空间。这对于从 Visual Objects 或其他不支持命名空间概念的系统移植过来的应用程序和库特别有用,因为这些系统中的所有类型都使用简单的类名。为了避免在可能有 100 或 1000 个代码文件中显式地提供命名空间名称,可以使用项目选项来代替。

使用带有命名空间的类型

通常,要在代码中使用一个类型,需要使用其完整的类名(包括命名空间部分):

FUNCTION Start() AS VOID
  LOCAL oUse AS OurCompany.CommonLibrary.GeneralUseType
  oUse := OurCompany.CommonLibrary.GeneralUseType{}

如果不包含命名空间部分,编译器就无法解析类名。但由于总是使用这么长的名称可能会很乏味,而且可能会导致代码臃肿,因此通常的做法是在每个代码文件的开头,在 USING 语句中指定常用的命名空间:

USING OurCompany.CommonLibrary
 
FUNCTION Start() AS VOID
  LOCAL oUse AS GeneralUseType
  oUse := GeneralUseType{}

USING 语句指示编译器在每次发现无法解析的类名时,尝试用给定文件中 USING 语句提供的所有命名空间名作为前缀来解析该类名。当然,如果代码中使用的两个或多个类型具有相同的简短名称,但名称空间不同,那么就不可能为每个类型都使用 USING 语句,因为这会导致名称冲突,使编译器无法区分每次使用的是哪一个确切的类。

 

另外请注意,任何介于 BEGIN...END NAMESPACE 语句之间的代码都会自动使用语句中提供的命名空间将其中定义的短类型名解析为完整类型名。因此,在这段代码中没有必要在类名中提供命名空间:

BEGIN NAMESPACE OurCompany.CommonLibrary
  CLASS GeneralUseType
  END CLASS
  CLASS AnotherClass
    METHOD Test() AS VOID
        LOCAL oUse AS GeneralUseType // 无需提供命名空间
        oUse := GeneralUseType{}
  END CLASS
END NAMESPACE

隐式命名空间查找

特别是对于提供了默认命名空间选项(见上文)的库,引用它们的应用程序可以使用其类的简短名称,而无需提供 USING 语句。启用 “Enable Implicit Namespace lookup(启用隐式命名空间查找) ”项目选项(该选项与 /ins 编译器选项相对应)就能实现这一目的。每个此类库都将其默认名称空间作为信息包含在程序集属性中,使用该选项时,编译器也会使用库中的默认名称空间自动解析类型名称。例如,在 VOSDK 类中就使用了这种方法,因此无需在引用这些库的应用程序的所有文件中提供 USING VO 语句,就可以使用这些库中定义的所有类。