今天在二十四画生的帖子里发现一个问题,有些Visual Basic的使用者认为VB的内置函数直接定义在Microsoft.Visual Basic命名空间中,因此不能直接在C#中访问。其实Microsoft.VisualBasic.dll里面的函数,都是定义在模块里的,C#中只要直接写模块名就可以访问到了。但在VB里确实可以只通过Microsoft.VisualBasic访问到这些函数,这使得一般的VB程序员不知道这些函数在模块里,也不知道背后的静态导入操作,宁愿写Microsoft.VisualBasic.IIf,也不写Interaction.IIf(其实后者才是最直接的写法)。
既然普遍有人对这个问题比较模糊,我来写一个帖子介绍VB模块与静态导入的知识。首先来看模块。VB用下列语法定义一个模块:
Public Module MyModule

End Module

VB的模块本质上是一个类(被VB加有特殊Attribute以示区别),但在VB中不能当作一个类型(即不能写在 As, Of, CType等语句的后面),当然也就不能实例化和继承。而且所有成员自动为Shared成员,以至于不用专门写Shared。模块的构造函数也自动为Shared构造函数。 这些特性使得模块成为无状态函数和数据的良好容器,与C# 2.0新引入的静态类其实是一类东西。只是,模块比静态类多了一步静态导入。
VB支持的“静态导入”特性(这最近也成为Java 5.0的新特性,但C#不支持),就是将一个类的可访问的静态成员导入全局命名空间,以至于不用书写类型名字就可以调用到这些静态成员。比如可以在代码开头写上
Imports System.Math 
Imports System.Console 

如此写完之后,调用Math.Sin就可以直接写成Sin;而调用Console.WriteLine也可以直接写成WriteLine。这对于定义常数的类尤为有用。
回到刚才的话题,由于模块只能定义静态成员,所以VB默认对所有模块自动实施一层静态导入,将模块中所有可访问的成员都导入到模块所在的命名空间中。这正是VB中所有内置函数不需要类型名作为前缀的原因。 有人说VB的模块是定义全局函数和变量的,但其实这里只不过有一次自动静态导入,使得语法上类似全局函数或变量而已。
比如Microsoft.VisualBasic.Strings.Left函数,由于String是模块,自动静态导入,就可以用Microsoft.VisualBasic.Left来访问。如果Microsoft.VisualBasic也被导入,那么就可以直接用Left这个名字来访问。在Windows Form中,由于窗体自己有Left属性,所以造成Left函数无法直接用函数名访问到,这时只要加上模块名,用Strings.Left就可以访问到了,无须像大部分VB初学者那样,用Microsoft.VisualBasic.Left这么长的名字访问。 要查看函数所属的具体类型,可以用VS.NET的对象浏览器查看Microsoft.VisualBasic命名空间。

知道这些之后,我们也可以利用模块自动静态导入的特性帮助我们实现一些语法上的简化。 比如我们有个类ComputerClass,给用户使用时我们希望用户直接使用ComputerClass的成员,因为计算机只有一个,不需要自行实例化。而ComputerClass的实现可能是有状态的,不能做成静态类。那么就可以写一个模块,在模块中用一个属性名叫Computer,实现ComputerClass类的单例模式。这样用户就可以不用ModuleName.Computer,而是只用Computer这个名称访问唯一的计算机对象,既保持了静态类的语法,又有单例模式的优点。这只是静态导入使用的一个很简单的例子,在VB的My命名空间上早已广泛采用。My的成员其实都是单例模式的对象。
对C#和C++/CLI来说,模块没有静态导入,就是普通的静态类,必须用模块名.成员名的方式访问模块中的静态成员,这其实就是二十四画生应该采用的语法,而不是用VB去封装一层。而Visual Basic的程序员也应当清楚,内置函数定义在模块里,是通过模块进行分类和组织的。在遇到名称冲突时,应当优先用“模块名.函数名”的方式来解决冲突,而不是错认为这些函数直接定义在Microsoft.VisualBasic中。
 posted on 2005-09-03 23:39  装配脑袋  阅读(3896)  评论(4编辑  收藏  举报