VB.NET经过长时间的发展,很多用户都很了解VB.NET了,这里我发表一下个人理解,和大家讨论讨论。促使我们从VB6转向VB.NET的一个***的原因就是VB.NET面向对象编程(OOP)这一概念的完全支持。然而,要运用这个功能,只学习一些新的关键字是远远不够的。面对这么多可供选择的新的功能,你可能会感到困惑。因此,我将在本文中说明如何在你的应用程序中运用面向对象的功能。我不会深入讲述每个新的功能(要进行深入讲述,用整本杂志的篇幅都不够),另外我也提供了代码例子,在可执行的代码中有注释,它们有助于你对一般概念的理解。你可能对我用的一些词不太熟悉,因此我提供了一个最常用的OOP术语表(见工具条“OOP术语表”)。
#T#你在应用程序中可能会经常用到的***个面向对象的语言的特征是方法重载(method overloading)。VB.NET面向对象可以让你用一个特定的名字定义多个方法或属性,只要它们的参数定义不同;这就是说,它们的参数的数量或类型必须是不同的。例如,一个类可以定义一个GetItem方法,它带有的参数可以是一个数字或字符串,我们根据参数类型来返回元素:
- Function GetItem(ByVal index As _
- Integer) As Object
- ' return an element by its index
- End Property
- Function GetItem(ByVal key As String) _
- As Object
- ' return an element by its key
- End Property
编译器通过查看参数的类型来调用正确的版本:
- res = obj.GetItem(1) ' numeric key
- res = obj.GetItem("Joe") ' string key
当你有一个可以采用任何数据类型的很普通的方法时,方法重载尤其有用——例如,一个将参数值添加到一个文本文件的Log方法。你可能想定义一个采用 Object参数的单独的版本,因为你想将任何类型的数据传递到这个方法: 然而,如果你将一个值类型的参数(一个数字、日期/时间、一个布尔值或一个结构)传递到一个Object参数,那么你就暗中强加了一个封装操作。.NET runtime必须用一个对象来封装值——这么做就会从托管堆(managed heap)分配内存,而且浪费了宝贵的CPU周期。
- Sub Log(ByVal value As Object)
- TW is a TextWriter object tw.Write("LOG:" & value.ToString()) End Sub
一个更好的方法就是为你支持的每种数据类型定义同一个方法的重载的版本。如果你不想为每种可能的参数类型写代码,你可以实现一个采用Long参数的版本(它可以处理Boolean、Short、Integer和Long类型的值)、一个采用Double参数的版本(它也可以处理Single类型的值)和另外两个分别采用DateTime值和Decimal参数的重载的版本。这四种版本可以处理最常用的值类型,而让采用一个Object参数的重载的版本来处理引用类型(如字符串)或更特殊的对象(如Person)。将一个字符串或一个特殊的对象传递到采用一个Object参数的版本不会增加CPU的费用,因为它没有强加封装操作。
VB.NET面向对象构造器提供了强大的类
在创建一个类库时,你应该用多个重载的方法,而不要用采用可选参数的一个单独的方法,因为有些.NET语言(C#最明显)不能识别可选参数。记住,两个重载的方法的不同不仅体现在它们的返回值或你用于每个参数前的ByVal/ByRef关键字上。(ByVal/ByRef关键字适用于VB.NET和其它一些.NET语言;C#可以让你定义两个只在ref或out关键字上有区别的方法。)
接下来我们要探究的一个面向对象的特征就是构造器(constructor)。VB.NET构造器是一个名为Sub New的过程,当客户端创建类的一个实例时,就会调用这个过程。如果你的代码不包含一个明确的构造器,VB.NET编译器就会自动添加一个缺省的构造器 ——一个不带任何参数的构造器。如果没有明确的(explicit)或隐含的(implicit)构造器,你就不能实例化类。VB.NET也可以让你定义一个带有参数的构造器,所以你可以让客户端实例化在有效状态创建对象所必需的字段:
- ' a read-only field can be set only
- ' from inside a constructor procedure
- Public ReadOnly Filename As String
- Sub New(ByVal filename As String)
- ' ensure filename isn't null
- If filename Is Nothing OrElse _
- Filename.Length = 0 Then
- Throw New ArgumentException("Invalid file name")
- End If
- ' assign to the read-only field
- Me.FileName = filename
- End Sub
带有参数的多个构造器通常有共同的代码——例如,验证一个或多个参数的代码。这时候,你就可以简化你的类的结构,让一个构造器调用另一个构造器:
- Public ReadOnly Overwrite As Boolean
- Sub New(ByVal filename As String, _
- ByVal overwrite As Boolean)
- ' a call to another constructor MUST
- ' be the first executable statement
- Me.New(filename)
- ' assign remaining fields
- Me.Overwrite = overwrite
- End Sub
当你既需要缺省的构造器,也需要一个或多个带有参数的构造器时,就会出现一个有趣的问题。在这种情况下,你必须明确声明一个空的Sub New过程,因为编译器不会自动为你创建它:
- Sub New()
- ' no need to add code here
- End Sub