首页

Click here to read ！
中 华 电 脑 书 库
http://www.pcbookcn.com
声明：本站所制作的书籍仅供个人学习,交流,研究之用。版权归原 作者和原出版物所有。如要作其它用途请直接与版权所有者联系。


(一)

VB.NET面向对象的实现(一)
编译：ZSC/太平洋网络学院

本文出自:http://www.vbip.com/books/1861004915/chapter_contents.asp

    在VB 6中面向对象的能力还不是很强，但随着VB.NET的出现，其面向对象的能力大大增强。VB.Net不仅为我们提供了新的面向对象的特性，而且它也改变了我们在VB6中实现一些特性时所用的方法。在本教程中我将带你浏览一下这些特性，并将涉及到新的性能以及现有特性的变化。

本简缩教程的内容有:

  1.创建类：类关键字、类及名空间、创建方法、创建属性、重载方法等。
  2.对象的生命周期：对象的构造、对象的终止
  3.继承：实现基本的继承、阻止继承、继承与辖域、保护方法、重载方法、重载与　　构造方法、创建基类以及抽象方法
  4.共享或类成员：共享方法、共享变量
  5.事件：共享事件、触发事件
  6.界面：怎样使用界面
  7.对象的处理：对象的声明等等
  8.交叉语言的继承：创建VB.NET的基类、创建C#子类、创建一个客户应用程序。
  9.可视化继承
  总结

创建类

    在VB以前的版本中创建类时，每一个类都有它自己的文件。如果VB.NET也使用这种方法的话，那VB.NET工程将是一个更大的面向对象工程因为它包含许多文件。但是幸运的是，VB.NET并不是采用这样方法来创建类。可以说这是一个创举，因为它不用为创建一个类就创建一个文件。而是在一个文件中包含许多类，这样就使得程序的可维护性更好了。
    另外VB.NET也提供了对.NET名空间概念的支持。VB.NET用于创建属性方法的语法也有些改变。类似于Visual C++，我们可以在类中重载这些方法。至此，我们对VB.NET的新特性已经可以略见一斑了。好吧，言归正转，现在可是为一个工程增加类。
其实，在VB.NET中增加一个类与在VB6增加一个类是很类似的。为了做到这一点我们需要先创建一个新的Winodws应用程序工程，具体操作是从菜单中选择Project(工程)->Add Class（增加类），这时就会弹出一个增加新项目的对话框，如图1所示。

（图1）

在图1的对话框中用户可以增加任意类型的项目到工程中。在本例子中是使用缺省的项目，即增加一个类模块。不管我们选择了哪种VB 代码文件(如表单、类、模块等等)，我们得到文件名字的扩展名都为.vb，如图1中的class1.vb。
这里值得指出的是，文件的类型是由它的内容决定的，而不是由文件的扩展名决定的。根据我们所选择的类型，IDE（集成开发环境）就在文件中创建不同的开始代码。
在如图1所示的对话框的最后一行给类命名为MyClass，然后点击Open键，这样一个新的文件就将增加到我们的工程中，它包含了以下简单的代码：

Public Class MyClass

End Class

在一个.vb文件中可以包含多个类、模块以及其它代码。接下来的设计过程实际上跟VB的差不多，我们可以手动增加其它的代码到这个文件中去。这里值得指出的是一旦在IDE创建类的时候它就会增加一个新的文件到工程中去。

类关键字

    在下面的例子中，代码包含了一个关键字End Class。这是一个新的关键字，使用它的目的是为了在一个源文件中包含多个类，这点正是VB.NET与VB6在创建类区别的精髓所在。每当我们在VB.NET中创建类的时候，我们只是简单地将所有的的代码包含在Class和End Class 之间。例子代码如下：

Public Class TheClass
Public Sub MyWorks()
End Sub
End Class

另外在一个特定的源文件(后缀名为.vb)中,我们可以使用多个Class...End Class块。

类与名空间

    名空间的概念是.NET环境重要内容，因为它可以提供哪个类可以被组成逻辑组的机理，并且使得这些类更容易的搜索以及管理。在VB.NET名空间是使用块结构来声明的。例如：

Namespace MyNamespace

Public Class MyClass

End Class

End Namespace

在Namespace...End Namespace块之间声明的任何类、结构等等将可以使用那个名空间被寻址。在本例子中，我们的类可以使用这个名空间来引用，这样定义一个变量就变成了：
Private obj As MyNamespace.MyClass

因为名空间是使用块结构来创建的，所以在单一的源文件中就不仅可以包含多个类，而且可以包含多个名空间。
同样，在一个相同名空间的类可以被创建在分隔的文件中。换句话说，在一个VB.NET工程中，我们可以使用在不同源文件中相同的名空间，而所有在这些名空间中的类将是那个相同名空间的一部分。
为了更好地理解，下面再给出一个源文件：

Namespace MyNamespace

Public Class MyClass

End Class

End Namespace

我们在工程中还有以下一个独立的源文件，其代码如下：

Namespace MyNamespace

Public Class MyOtherClass

End Class

End Namespace

以上的两短段代码是为了说明在同一个名空间MyNamespace中有两个类：MyClass和MyOtherClass。
这里还需指出，在缺省状态下，VB.NET工程有一个根名空间（root namespace），它实际上是工程属性的一部分。这个根名空间使用了与工程相同的名字。所以当我们使用名空间块结构的时候，我们实际上是增加到根名空间上去。因此，如果你的工程命名为MyProject，那么我们可以这样来定义一个变量：
Private obj As MyProject.MyNamespace.MyClass

当然你也可以改变根名空间，具体操作可以使用菜单选项：Project（工程）->Properties（属性）。

[下一页]


(二)

VB.NET面向对象的实现(二)
编译：ZSC/太平洋网络学院

创建方法

    在VB.NET中方法的创建还是跟在VB6中的一样，你可以使用Sub或者Function关键字。Sub和Function的区别是：用Sub来创建一个方法，它将不返回数值；若是利用Function来创建一个方法，它将返回一个数值作为结果。例如：

Sub MyWorks()
End Sub

Function MyValue() As Integer
End Function

在VB.NET中我们仍可以使用辖域关键字，这跟在VB 6中的差不多，只是多了Protected。具体的辖域关键字有：
Private表明只能调用类中的代码；
Friend 表明可以在我们的工程/组件中调用代码；
Public 表明可以在我们的类外部调用代码；
Protected是VB.NET新增的，这个我们将在讨论继承的时候再具体阐述。
Protected Friend 表明只能在我们的工程/组件调用代码以及我们的Subclass的代码。同样我们将在讨论继承的时候再具体阐述。
缺省地，方法的参数是声明为ByVal而不是ByRef。当然，我们仍然可以通过使用ByRef关键字来重载这个缺省的行为。

创建属性

    以前我们创建属性的时候是使用Property Get和Property Let，但现在在VB.NET中已经将它集成到一个结构中去了。例子如下：

Private mystrName As String

Public Property Name() As String
Get
Return mystrName
End Get
Set
mystrName = Value
End Set
End Property

缺省的属性

    在VB6中创建类的时候，我们可以为类声明一个缺省的方法或者属性。具体做法可以菜单选项：Tools（工具）->Procedure Attributes（过程属性）并设置Procedure ID为缺省值。
VB.Net用两种方法改变了这种行为。第一，使用一个缺省的关键字来创建缺省的属性，使得声明更加清晰直观。但是，VB.NET还给缺省的属性引入了一种新的限制，即属性必须是一个属性阵列。
属性阵列实际上就跟数组一样，有一个索引。在选择或者列表对象中的项目属性就是一个例子：
strText = MyList.Item(5)
这个项目属性没有单一的数值，而是有一组的属性，它们可以通过索引来访问。
通过使用属性阵列作为缺省属性，我们就允许程序语言避免了在使用缺省属性的多义性。正如我们在VB6中所知道的，关键字Set的限制是关键。下面再看看以下的语句：
MyValue = MyObject
这句是指对象MyObject还是指它的缺省属性呢？为了识别它，在VB6中使用了Set命令来处理对象，如不使用Set就是指缺省的属性。在VB.NET中这条语句是指对象，因为缺省的属性是要被索引的。为了得到缺省的属性，我们要编写以下代码：
MyValue = MyObject(5)
因为索引是一个清楚的指示器（我们指缺省的属性，而不是MyObject本身），所以就不会有多义的存在了。
VB.NET这样的改变就意味着属性阵列过程必须接收一个参数。例如

Private MyMoney(100) As String
Default Public Property Money(ByVal Index As Integer) As String
Get
Money = MyMoney(index)
End Get
Set
MyMoney(index) = Value
End Set
End Property

最后，看起来这些代码比VB6更清楚，但也会丢失了一些灵活性。在过去，我们喜欢使用缺省的属性。举个例子，我们在用GUI控件的时候经常使用缺省的属性，比如缺省的文本属性。
TextBox1 = MyText
但是这在VB.NET中已经不再有效，因为文本属性不再是一个属性阵列，相反地我们必须使用属性名字。

重载方法

    VB.NET的另外一个新特性是有重载方法的能力。重载的意思是我们可以在一个类中多次声明相同名字的方法只要每一次的声明都有不同的参数列表。
不同的参数列表意味着在列表中不同类型的数据类型。现在让我们先看看以下的方法声明：
Public Sub MyMethod(X As Integer, Y As Integer)
这种方法的参数列表可以看成(integer,integer)。为了重载这种方法，我们必须使用不同的参数列表，例如(integer,double)。当然你还可以改变一下数据类型的顺序，比如(integer,double)和(double,integer)是不同的，这两种也是重载。重载不能只是通过改变函数的返回类型来实现，而是要求参数的数据类型不同。
作为一个例子，假如我们想提供一个搜索的功能并且根据一些条件返回一组数据，具体代码应该为：

Public Function MyFindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

在VB 6中，如果我们想基于一些条件增加一个新的搜索选项，就必须增加一个不同名字的函数，也就是说VB 6还没有具备重载的能力。但是现在在VB.NET中，我们可以简单地重载已经存在的函数，这一点和Visual C++很是相似。

Public Overloads Function FindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

Public Overloads Function FindData(ByVal Age As Integer) As ArrayList
（搜索数据并且返回结果）
End Function

仔细观察可以发现两种方法的声明都是有相同的方法名字。这一点在VB 6中就不行的，它要求每一个方法名字都不一样。但是，在VB.NET中就允许存在相同名字的方法，但其参数要求是不同的。值得一提的是，每一个声明都要加入Overloads关键字。
当重载一个方法的时候，我们可以使用Public、Friend等等的辖域关键字让它有不同的作用域，具体做法只要使用不同的参数列表即可。这就意味着我们可以改变MyFindData方法，使它有不同的作用域：

Public Overloads Function FindData(ByVal Name As String) As ArrayList
（搜索数据并且返回结果）
End Function

Friend Overloads Function FindData(ByVal Age As Integer) As ArrayList
（搜索数据并且返回结果）
End Function

有了这个改变，在VB.NET工程中其它代码可以使用MyFindData。MyFindData只需要接收一个整型数据作为参数即可。


(三)

VB.NET面向对象的实现(三)
编译：ZSC/太平洋网络学院

对象的生命周期
在VB 6中，对象有一个很清楚的定义以及很容易理解的生命周期的概念，对象的生命周期是由下面的事件来定义的。

事件描述
Sub Main 运行时它将作为组件被装载，并且是在对象创建之前装载。
Class_Initialize 它是在对象中其它代码运行之前运行。当对象被创建的时候它被运
行程序所调用。
Class_Terminate 是在对象中其它代码运行之后再运行。当对象被卸载的时候被运行
程序调用。

在VB.NET，对象也有生命周期的概念，但是已经跟以前大不一样了。特别地，我们不再有相同的组件级的Sub Main（它作为一个DLL被装载）的概念，并且Class_Terminate事件也被改变了，而Class_Initialize事件被成熟的构造函数方法所取代。值得指出的是，这个构造函数方法可以接收参数。
现在在VB.NET中，我们定义一个生命周期只需要用了一个New事件，这个New事件是在对象中其它代码之前运行的，并且在对象被创建的时候被调用。
从VB 6到VB.NET确实变化很大，下面我们具体讨论。

构造

对象构造是在我们创建一个类新的实例的时候被触发的。具体可以使用关键字NEW来实现它。

Sub Main
自从VB 6基于COM，创建一个对象将触发一个Sub Main过程运行。这将发生在一个对象从一个给定的组件（通常为DLL）创建来的时候。在创建对象之前，VB 6运行程序将装载DLL（动态连接库）并运行Sub Main过程。
.NET通用语言运行程序处理组件采取不同的方法，当然VB.NET也是这样的。这就意味着没有Sub Main过程在组件装载时候被调用。实际上，Sub Main只使用在当一个应用程序开始的时候。当另外的组件被应用程序装载的时候，只有在类中的代码才被调用。
其实在VB6中依靠Sub Main是不明智的做法，因为代码将在所有错误操作之前被运行。Sub Main中的Bugs是难以在VB6中调试。如果我们不得不使用依耐于Sub Main概念的代码来初始化，那么我们需要在VB.NET执行一个工作区。
在每一个类中从构造函数方法中调用一个方法是很容易做到的。举个例子，我们可以在一个模块中创建一个有效的代码：

Public Module CentralCode
Private blnHasRun As Boolean
Public Sub Initialize()
If Not blnHasRun Then
blnHasRun = True
（在这里作初始化工作）
End If
End Sub
End Module

这个程序是被设计为只运行一次，不管是怎么被调用。我们可以从类中的每一个构造函数来使用这个方法。比如 ：
Public Class TheClass
Public Sub New()
CentralCode.Initialize()
（这里加入另外的工作）
End Sub
End Class
以上的代码虽然作了一些额外的工作，它跟使用VB6类型的Sub Main程序达到同样的效果。

New方法
就象Sub Main，Class_Initialize是在其它VB6类中的代码运行之前被调用的。此外，它是在错误处理之前被调用的，所以使得调试变得很难，而错误作为一般的错误显示在客户端来实例化对象。另外地，Class_Initialize不用参数，这意味着在VB6中没有方法可以在对象被创建的时候用数据来进行初始化。
VB.NET剔除了Class_Initialize而采用完整的构造函数方法。这个构造函数有完整的错误处理能力以及可以接收参数。所以我们可以在创建对象的时候来对它们进行初始化，这是VB.NET一个十分重要的特性。VB.NET中构造函数方法是Sub New。
Public Class TheClass
Public Sub New()
(在这里初始化对象)
End Sub
End Class

利用这种类型的构造函数，可以如下创建类的实例：
Dim obj As New TheClass()

这个例子类似于在Class_Initialize创建一个VB6代码。
但是，经常地，我们在创建对象的时候往往要用数据来初始化对象。我们可以从数据库中来装载一些数据，或者我们可以直接为对象提供数据。不管用什么方法，我们是想在对象被创建的时候为它提供一些数据。
为了做到这点，可以增加参数列表给New方法：
Public Class TheClass
Public Sub New(ByVal ID As Integer)
(在这里使用ID数值来初始化对象)
End Sub
End Class

现在我们来创建类的一个实例，并且为对象提供数据，代码如下：
Dim obj As New TheClass(42)

为了增加灵活型，我们可以接收可选的参数数值。为了实现这个，可以有两种方法：通过使用Optional关键字来声明一个可选择的参数，或者通过重载New方法。为了使用Optional关键字，我们简单地声明可选择的参数，代码如下：
Public Sub New(Optional ByVal ID As Integer = -1)
If ID = -1 Then
（这里可以初始化对象）
Else
（这里可以使用ID数值来初始化对象）
End If
End Sub

这种方法太过于理想化了，但是，既然我们不得不检查是否参数是（不是）已经提供，然后决定怎样初始化对象。New方法又两个方法可以实现。第一种是对于每种行为类型而言的，它可以通过重载来实现：
Public Overloads Sub New()
（这里可以初始化对象）
End Sub

Public Overloads Sub New(ByVal ID As Integer)
（这里可以使用ID数值来初始化对象）
End Sub

这种方法不仅可以避免有条件的检查以及简化了代码，而且它还使得对于客户代码对象的使用都变得更清晰。这个重载New方法可以使用参数也可以不用参数，有更大的灵活性。
实际上，通过重载，我们可以创建许多不同的构造函数，也可以利用许多种不同的方法来初始化我们的对象。
在VB.NET中构造函数方法是可选的。但是只有一个例外，那就是当我们使用继承的时候，父类就只有一个构造函数需要参数。在本教程的后面我们将讨论继承。


(四)

VB.NET面向对象的实现(四)
编译：ZSC/太平洋网络学院

对象的终止
在VB6中对象是在最后引用移除后被终止的。换成另外一句话说，当没有其它代码引用这个对象的时候，这个对象将自动终止。具体触发这个终止事件的是Class_Terminate。这种方法是使用引用计数来决定对象是否被终止的，是VB的一个直接的产品，它跟COM有紧密的联系。
所以我们在需要终止这个对象的使用就调用Class_Terminate事件，使得很容易控制对象。但是它也有不足之处。很明显地，虽然在两个对象之间创建循环引用是很容易，但是它们将在内存中永远地被运行。这正是在VB6中其中一种导致内存泄漏的缺陷。
这个内存泄漏问题在VB6以前的版本中是无法克服的。在VB6中，循环引用只发生在不同组件上。在VB6中，由相同的组件中的类创建而来的类将被自动终止，即使它们有循环引用。但是，如果对象来自不同的组件，循环引用问题就依然存在。这个是个很大的问题，它给许多VB开发人员带来了麻烦。所以，在VB6中程序不得不寻求各种方法来终止对象。
不象COM，.NET不是使用引用计数来决定对象是否被终止的。取而代之的是，它使用了一个有名的“垃圾收集”方案来终止对象。可能听到“垃圾收集”方案，您会云里雾里的，它的意思实际上是在VB.NET中我们不用预先定一个对象的终止方案，因此我们就不能准确地预测对象什么时候被终止的。下面我们详细探讨一下“垃圾收集”。 “垃圾收集”
在.NET中，引用计数不是一个基础功能部分。相反地，对象是通过一个“垃圾收集”机理被终止。在某特定的时间（这决定特殊的规则），一个任务会在所有的对象中运行来查找哪些已经没有被引用的对象，并且将这些对象终止，即所谓的“垃圾收集”，名字是有点土，但更形象化。
由以上的讨论我们可以知道，我们不能很准确地知道对象是在什么时候被终止的。我们除去对象的所有引用之后，并不是意味着对象快速地被终止了。此时对象还存在于内存中，直到垃圾收集处理程序运行之后才将它从内存中清除。
垃圾收集的主要好处是它清除了由引用计数带来的循环应用问题。如果两个对象互相有引用，并且在程序中没有其它互相引用的代码时，垃圾收集程序就会发现它们并将它们终止。这一点在COM中是不可能做到的，因为它们将在内存中永远存在。
垃圾收集还有另外一个潜在的性能优点：在对象被取消引用的时候不用花很多的精力在终止对象上；利用了垃圾收集，这个终止处理过程是在应用程序处于空闲状态发生的，所以它减轻了对用户的影响。但是，垃圾收集也会发生在应用程序处在运行装载的时候，这时候系统将会运行在较低的系统资源下。
另外，我们可以通过编写代码来手动触发垃圾收集处理程序：
System.GC.Collect()

以上这个处理过程要花一些时间，但是我们在想终止对象的时候也不必每次都执行这个处理过程。我们最好是这样来设计我们的应用程序：在最后终止对象的时候才将对象从内存在清除。

Finalize方法
这个垃圾收集机理提供了一些功能，这些功能可以跟VB6中的Class_Terminate事件相媲美。当对象被终止的时候，垃圾收集处理的代码将调用Finalize方法，它就象Class_Terminate一样可以进行一些最后的内存清理工作。
Protected Overrides Sub Finalize()
（此处可以进行一些内存清理工作）
End Sub

以上的这些代码可以使用Protected（保护）作用域也可以使用重载关键字。这里值得指出的是，这种方法是在对象被垃圾收集机理终止之前被调用的，所以它跟Class_Terminate很是相似。
但是，我们还需要记得这种方法可以在对象被取消引用后被调用，它是通过最后一段客户代码来实现的。

实现Dispose方法
在有些场合中Finalize方法是不可接收的。如果我们有一个对象，它是使用一些非常有限的宝贵的系统资源，比如数据库连接、文件处理或者系统锁住等等。这时候我们就需要确保系统资源在对象被取消引用的时候是否被释放。
为了实现这个目的，我们可以执行这样一个方法，它可以被客户代码调用来强迫对象被清除并且释放系统资源。虽然这不是一个很好的解决方案，但是它确实是很有效的。习惯上，这个方法就取名为Dispose，其代码如下：
Public Sub Dispose()
（此处可以进行一些清除工作）
End Sub

在必要的时候，我们可以调用这个方法来确保内存清除工作的进行。
从上面的讨论中，我们可以深刻地体会倒VB6和VB.NET在创建类和对象的一些变化。下一个教程我们将详细讨论一下对象的继承。


(五)

VB.NET面向对象的实现(五)
编译：ZSC/太平洋网络学院

继承

本教程设计的内容有：基本的继承、阻止继承、继承与辖域、保护方法、重载方法、重载与构造方法、创建基类以及抽象方法。
当VB面向对象特性变得越来越强大的时候，我们会发觉VB缺少了继承的内容。继承是类为了得到父界面或者现有父类的一种能力。当创建一个新的从父界面或者现有父类继承而来的类的时候，我们就为原来的类创建了一个子类。这就是我们所知的父子关系。
现有许多关于继承的术语，但是很多是多余的。原来的类，即我们所继承的界面和行为可以由以下的几种互换的说法：
Parent class （父类）
Superclass （超级类）
Base class （基类）
而由原来的类继承而来的界面或者行为也有以下的几种互换的说法：
Child class （子类）
Subclass （次类）
继承是用于生物学上的名词。比如，狗是犬科动物而犬科动物又是哺乳动物，因此作为犬科动物，狗继承了哺乳动物所有的属性和行为，这就是继承的原始涵义，即生物学上的继承。在这里借用继承这个名词用于面向对象中，具有许多相似之处。
为了在VB中满足许多程序设计人员能够象在Visual C++中利用面向对象的功能，特别是继承的功能，VB.NET开始有了继承的概念。但是VB.NET还是不允许多重继承，即子类不能有多个父类继承而来，它只能继承一个父类。而VB.NET允许深度的继承分级结构，即一个子类可以有另外一个子类继承而来；但是VB.NET还是不允许同时继承多个父类。
在父子关系中，父对象可以拥有多个子对象，而子对象虽然都是由父对象继承而来但是它们是不同类型的。举个例子，一群子女虽然都是由父母生育的，但是他们还是有不同的相貌、性格等等。
接下来我们详细介绍VB.NET的继承。

实现基本的继承

为了探讨继承，我们先考虑以下一个商业的例子：每一个定货都有一个线路项，可能有产品线路项和服务线路项。这两种线路项是有些不同的。但是当我们在分开实现ProductLine和ServiceLine类的时候，我们就会发现其实它们有许多相同之处。如果分开编写这两个类的代码，不仅编程效率低，而且程序代码也难以维护，所以最好的方法就是使用它们一些相同的代码。
为了实现使用相同的代码，继承就起了很大的作用了。使用继承，我们可以创建一个LineItem类（父类），它包含了所有的共用代码。然后我们再创建ProductLine和ServiceLine子类，这两个类是由LineItem继承而来的。这样它们就可以自动地获得所有的共用代码了。
假如LineItem类为：
Public Class LineItem

Private mintID As Integer
Private mstrItem As String
Private msngPrice As Single
Private mintQuantity As Integer

Public Property ID() As Integer
Get
Return mintID
End Get
Set
mintID = value
End Set
End Property

Public Property Item() As String
Get
Return mstrItem
End Get
Set
mstrItem = Value
End Set
End Property

Public Property Price() As Single
Get
Return msngPrice
End Get
Set
msngPrice = Value
End Set
End Property

Public Property Quantity() As Integer
Get
Return mintQuantity
End Get
Set
mintQuantity = Value
End Set
End Property

Public Function Amount() As Single
Return mintQuantity * msngPrice
End Function

End Class

这个类中有所有的共用代码以及一些基本的数据区域和用于计算项目价钱的方法。
如果线路项对于产品而言，我们则需要再增加一些代码。这个项目的数值应该要验证一下确保它指一个实际的产品，并且可能的话我们也想提供产品的描述，所以ProductLine类的代码如下：
Public Class ProductLine

Inherits LineItem

Private mstrDescription As String

Public ReadOnly Property Description() As String
Get
Return mstrDescription
End Get
End Property

Public Sub New(ByVal ProductID As String)
Item = ProductID
（此处你可以从数据库中转载产品数据）
End Sub

End Class

上面语句中我们已经使用的继承语句：
Inherits LineItem
这条语句使ProductLine类获得了LineItem类的所有的界面元素或者行为。所以我们可以如下编写客户代码：
Protected Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim pl As ProductLine

pl = New ProductLine(23abc
MessageBox.Show(pl.Item)
MessageBox.Show(pl.Description)
End Sub

以上的代码使用了从LineItem类继承而来的Item属性以及ProductLine中的Description属性。
类似地，我们可以编写ServiceLine:
Public Class ServiceLine

Inherits LineItem

Private mdtDateProvided As Date

Public Sub New()
Quantity = 1
End Sub

Public Property DateProvided() As Date
Get
Return mdtDateProvided
End Get
Set
mdtDateProvided = Value
End Set
End Property

End Class

这里要注意的是，上面的继承语句表明ServiceLine是LineItem的子类。而DateProvided属性是从LineItem类中加入的界面。


(六)

VB.NET面向对象的实现(六)
编译：ZSC/太平洋网络学院

继承

阻止继承

在缺省状态下，我们创建的任何类都是作为一个基类使用的，而其它的类是有这个基类创建而来的。有时当我们想创建一个类，而这个子类不能被继承。为了做到这一点，我们可以在类的声明中使用NotInheritable关键字。
Public NotInheritable Class ProductLine

End Class

当使用了这个关键字，其它代码都不能使用Inherits关键字来创建一个由这个类继承而来的子类。

继承和辖域

当我们通过继承来创建一个子类的时候，新类就可以从父类中得到了所有的Public(公共)和Friend（友）方法、属性和变量。如果你在父类中声明一个Private（私有）的方法、属性和变量，那么在新的子类中就不能得到这个类的方法、属性和变量。
当然也有个例外，就是New方法。构造函数方法必须在每一个子类中重新编写。这个内容我们在本教程的后面将深入讨论。
举个例子，我们可能从LineItem类中重写Amount方法，具体如下：
Public Function Amount() As Single
Return CalcAmount
End Function

Private Function CalcAmount() As Single
Return fQuantity * fPrice
End Function

从这个改变中，我们可以看到公共的方法Amount使用了Private方法来工作。
当我们利用LineItem来创建子类ServiceLine的时候，任何的ServiceLine对象都有一个Amount方法，因为它在基类中声明为Public。另外一方面，这个CalcAmount方法被声明为Private，所以所有的ServiceLine类和任何的客户代码都不能访问它。
这里值得一提的是，既然Amount方法存在于LineItem类中，它就可以访问CalcAmount方法即使在ServiceLine类中不能看到这个方法。
举个例子，在我们的客户代码中我们可以这样做：
Protected Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim sl As ServiceLine

sl = New ServiceLine()
sl.Item = delivery sl.Price = 20
sl.DateProvided = Now
MsgBox(sl.Amount, MsgBoxStyle.Information, amount)

End Sub

结果显示在一个消息框中，这样就阐明了CalcAmount方法被成功调用了，虽然客户代码和ServiceLine代码没有直接调用它。

Protected(保护)方法

有时，Public和Private并不能满足我们的要求。如果我们想声明一些变量或者方法为Private，那么这些变量和方法就只能在我们的类中使用；但是当我们声明一些变量和方法为Public或者Friend，那么这些变量和方法就可以在子类和客户代码中使用。但是，有时有声明一些变量和方法，让它们在子类中有效，而在客户代码中不能用，该怎么办呢？这里可以使用Protected辖域。当变量或者方法被声明为Protected的时候，对于任何类外部的代码将不能调用，但是还是可以被由它继承而来的子类调用。
举个例子吧，如下：
Public Class ParentClass
Protected TheValue As Integer
End Class

Public Class SubClass
Inherits ParentClass

Public Function GetValue() As Integer
Return TheValue
End Function
End Class

在上面的代码中我们有一个父类，它有一个Protected成员变量TheValue。这个变量在任何的客户代码中都不能被调用。但是这个变量对于任何的子类都是有效的因为它继承了这个父类。在这个例子中，SubClass有一个Public方法返回了Protected变量的数值，但是这个变量对于类的外部任何客户代码都是无效的。


(七)

VB.NET面向对象的实现(七)
编译：ZSC/太平洋网络学院

共享或类成员

随着对象的功能越来越强大，我们有时想访问一些变量、函数或者程序而不需要一个实际的对象实例。在以前，我们可以键入这类型的代码到一个代码模块中，而不管程序是否跟一些类有关。

共享方法

在VB.NET中我们有了一个较好的改变。不仅一个类可以拥有所有正常的方法和属性（这些方法和属性可以由创建类的实例来实现）而且它们可以拥有一些不需要创建类的实例的方法，这些方法就是本教程要介绍的共享方法。这些方法在其它的编程语言中也称为静态方法或者类方法。

一个共享方法不能作为一种普通的方法，通过一个对象的实例来访问，而是可以从类直接访问。下面是共享方法的一个简单的例子：

Public Class Math

Shared Function Add(ByVal a As Integer, ByVal b As Integer) As Integer

Return a + b

End Function

End Class

我们可以不用实例化一个Math对象，就可以访问，代码如下：

Dim result As Integer

result = Math.Add(5, 10)

现在请再仔细看看，这里我们不是使用一个变量，而是直接使用类的方法。如果用通常的方法就将导致错误，但是利用了共享方法一切都变得可以接受了。

共享方法不仅可以通过通常的方法来访问而且可以在不需要创建一个对象的条件下提供访问的功能。实际上，当一个共享方法被调用的时候，没有任何对象被创建，它就象再模块中的一个程序可以直接被调用。

共享方法和其它普通的方法一样也可以被重载，所以可以利用相同的共享方法来创建一系列变化的方法，每一种方法有不同的参数列表。

共享方法的缺省的辖域是Public。我们也可以载声明中将共享方法设置为Friend、Protected或者Private。实际上，当重载方法的时候，只要参数列表不同我们就有不同的作用域。

究竟共享方法是如何使用的呢，下面我们看看一个例子。当我们想为输入打开一个文本文件的时候，我们可以在File类中使用一个共享代码，如下：

Dim infile As StreamReader = File.OpenText(words.txt)

Dim strIn As String

str = infile.ReadLine()

这里没有任何的类型的文件被创建。OpenText方法是一个共享方法，它打开一个文件并且返回一个StreamReader对象。另外一个例子来自System.Guid数据类型。这个类描述了一个全局的独特的用户ID（GUID）数值，但是我们可以通过一个共享方法来创建一个新的方法。

Dim guidID As Guid()

guidID = Guid.NewGuid()

这个NewGuid方法是直接从Guid类中调用的。它创建了一个新的Guid对象并且返回一个数值。


(八)

VB.NET面向对象的实现(八)
编译：ZSC/太平洋网络学院

共享或类成员

共享变量

我们还可以创建另外一种共享成员。有时候类的所有实例需要共享一个数值，有时候每个特定类型的对象要共享相同的变量，这些时候都可以通过使用共享变量来实现目的。

一个共享变量可以使用Shared关键字来声明，这一点很象共享方法的声明：

Public Class MyCounter

Private Shared mintCount As Integer

End Class

跟共享方法一样，我们也可以根据需要来设置共享变量的作用域。在缺省状态下两者就不一样了，共享方法是Public,而共享变量是Private。

总而言之，我们要养成一个好的习惯：定义方法和变量的作用域而不使用缺省值，以避免混乱。

关于共享变量的一件重要的事情是它们在所有类的实例中都是公用。我们可以键入如下的代码来加强我们的类：

Public Class MyCounter

Private Shared mintCount As Integer

Public Sub New()

mintCount += 1

End Sub

Public ReadOnly Property Count() As Integer

Get

Return mintCount

End Get

End Property

End Class

仔细看看上面的代码：当我们为类创建了实例时，计数器就增一。+=操作符是一个在VB.NET新有的。

在任何时候我们可以通过Count属性来取出count数值。这样，如果我们运行下面的客户代码，我们可以得到结果为3。

Protected Sub Button4_Click(ByVal sender As Object, _

ByVal e As System.EventArgs)

Dim obj As MyCounter

obj = New MyCounter()

obj = New MyCounter()

obj = New MyCounter()

MsgBox(obj.Count, MsgBoxStyle.Information,counter)

End Sub

如果我们再次运行这段程序，将可以得到6、9等等。只要我们的应用程序继续运行计数器就保持有效，也就是说一旦我们结束应用程序计数器就不再起作用。

这项计数对于服务器的处理过程是十分有用的，因为它可以轻松地不停地进行计数。这个数值只有在处理过程重新开始地时候才被复位。

全局变量

对于共享变量另外一个通常的应用是提供了全局变量的类型。给定一个Public作用域的共享变量：

Public Class TheClass

Public Shared MyGlobal As Integer

End Class

我们可以在客户代码中使用这个变量。

TheClass.MyGlobal += 5

这个变量将在我们应用程序的任何地方都是有效的，它提供了一个很好的机理来在组件、类、模块等等之间来共享数值。


(九)

VB.NET面向对象的实现(九)
编译：ZSC/太平洋网络学院

事件

在VB.NET中，继承是完全支持事件的。如果一个基类定义了一个Public事件，那么这个事件可以通过基类的代码或者任何由基类继承而来的子类所触发。

举个例子吧，我们可以先定义一个基类，代码如下：

Public Class Parent

Public Event ParentEvent()

Public Sub DoEvent()

RaiseEvent ParentEvent()

End Sub

End Class

很显然，类中的代码可以触发ParentEvent事件。我们还可以这样来创建一个子类：

Public Class SubClass

Inherits Parent

Public Sub DoSomething()

RaiseEvent ParentEvent()

End Sub

End Class

这个子类是通过使用Inherits关键字继承而来的，它不仅得到了父类的属性和方法，而且继承了基类的事件。

事件可以定义任何的作用域。如果定义为Private事件，那么它就只可以通过发送对象来获得，但是Public事件就可以被任何对象访问。而Protected事件可以通过定义类或者子类来创建对象进行访问。另外Friend 事件可以被VB.NET工程中的任何对象访问。

不象方法，事件不能使用Overloads关键字来进行重载。一个类可以使用任何特定的名字来定义一个事件。因为任何子类将自动从父类重得到事件，所有Override关键字就显得没什么作用，故不能用于事件中。

共享事件

事件可以定义为Shared。共享方法可以触发共享事件，而不能触发非共享事件，具体例子如下：

Public Class EventSource

Shared Event SharedEvent()

Public Shared Sub DoShared()

RaiseEvent SharedEvent()

End Sub

End Class

一个共享事件也可以由共享方法或者非共享方法来触发，下面是相应的例子：

Public Class EventSource

Public Event TheEvent()

Shared Event SharedEvent()

Public Sub DoSomething()

RaiseEvent TheEvent()

RaiseEvent SharedEvent()

End Sub

Public Shared Sub DoShared()

RaiseEvent SharedEvent()

End Sub

End Class

如果你想从一个共享方法中触发一个非共享事件就将导致一个语法错误。


(十)

VB.NET面向对象的实现(十)
编译：ZSC/太平洋网络学院

事件

在不同工程之间触发事件

在不同工程之间完成触发事件的工作，这在VB中是不能做到的。但是在VB.NET中我们可以使用Event和RaiseEvent关键字并且使用Delegate关键字来实现它。如果你想从VB.NET工程中触发一个事件并且在另外一个工程中收到这个触发，我们就必须使用事件和Delegate的概念。

执行远程事件源

当我们仍要使用RaiseEvent语句来触发事件的时候，如果要在其它VB.NET工程中的代码接收代码我们需要采用不同的方法来声明事件。特殊地，我们需要在类外部我们要触发事件的地方通过使用Delegate语句定义事件作为delegate。

接着创建一个新的类库，将它命名为EventSource并且增加一个简单类命名为RemoteClass。

假定我们想触发一个事件，这个事件返回一个字符串参数。我们首先要利用参数的类型来声明一个Delegate:

Public Delegate Sub RemoteEventHandler(ByVal SomeString As String)

通常情况下VB.NET会自动创建这个Delegate。然而，有时候这个Delegate不能从其它工程中进行访问，所以我们还是对它进行显式的声明。

以下是我们创建的类，它可以触发事件：

Public Class RemoteClass

Public Event RemoteEvent As RemoteEventHandler

Public Sub DoSomething()

RaiseEvent RemoteEvent（anyevent）

End Sub

End Class

这段功能是否成功的实现取决于事件本身的定义：

Public Event RemoteEvent As RemoteEventHandler

这个事件并没有显式地定义它的参数，而是依赖于Delegate来定义。反而，这个事件是定义为一个特殊的类型，即我们刚才定义Delegate的类型。

另外，用于触发事件的代码只是应用了一个简单的RaiseEvent语句：

RaiseEvent RemoteEvent（anyevent）

这条语句提供的参数数值用于当事件被触发时的返回值。

接收远程事件

在单一的VB.NET工程中，我们可以编写代码类接收事件。具体可以增加一个Windows应用工程来解决，你可以右击它并选择Set As Startup Project选项，这样它就可以在按F5的时候被运行了。

为了访问触发事件的类，我们必须给EventSource工程增加一个引用，具体操作如下：选择菜单项Project（工程）->Add Reference（增加引用）。

之后，我们可以增加一个按钮到窗体上，并且打开窗体的代码窗口，再引入以下的远程名空间：

Imports System.ComponentModel

Imports System.Drawing

Imports System.WinForms

Imports EventSource

在窗体A中，我们可以使用WithEvents关键字来定义远程类。

Public Class FormA

Inherits System.WinForms.Form

Private WithEvents objRemote As RemoteClass

当objRemote项在左上角的类名字下拉表中被选择的时候，我们可以在代码窗口右上角的方法名字下拉列表中看到事件的列表。当我们选择了这个选项，以下的代码就将被创建：

Public Sub objRemote_RemoteEvent() Handles objRemote.RemoteEvent

End Sub

不幸的是，这些代码是错误的，因为它没有提供我们所传递的参数。为了解决这个问题我们只需要增加参数到声明中去即可：

Public Sub objRemote_RemoteEvent(ByVal Data As String) _

Handles objRemote.RemoteEvent

Messagebox.Show(Data)

End Sub

我们还需要增加代码来在对话框中显示结果。具体做法为：增加一个按钮到窗体中去，并为按钮增加以下的代码：

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)

objRemote = New RemoteClass()

objRemote.DoSomething()

End Sub

至此我们就成功完成了从一个工程中触发事件，并且在另外一个工程中接收到这些触发的事件了。


(十一)

VB.NET面向对象的实现(十一)
编译：ZSC/太平洋网络学院

界面

VB允许我们创建有多个界面的工程。为完成这个我们可以使用Implements关键字。在类要执行一个新界面的时候，我们需要编写代码来执行界面上的每一个方法。当继承提供了一个完美的变化后，我们可能还想在我们的对象中执行多个界面。VB.NET保存了Implements关键字，这就使得界面的概念提高了并且比起VB6来简单多了。

怎样处理界面

VB.NET进入了一个形式化的结构用于定义界面。它改变了用在类中的语法来执行界面，使得代码更加直观和清晰。

界面声明

最直观的改进是引入了一个用于声明界面的正式的语法，它是使用了Interface关键字的，如下：

Public Interface MyInterface

Event MyEvent()

Sub MyMethod()

Function MyFunction(ByVal Param1 As Integer) As Integer

Property MyProperty() As String

End Interface

这种方法比起VB6的更正式。它不仅可以声明子函数、函数和属性方法，而且可以声明事件作为界面的一部分。

重载方法

方法（子函数或者函数）可以使用Overloads关键字来声明。这个用于重载的准则跟前面几个教程中的教程是一样的。每一个重载声明必须有一个特别的参数列表，这依赖于参数的数据类型。

以下的例子正式使用重载方法来声明一个界面：

Public Interface MyInterface

Overloads Sub MyMethod()

Overloads Sub MyMethod(Data As String)

Overloads Function MyFunction(ByVal Param1 As Integer) As Integer

Overloads Function MyFunction(ByVal Param1 As Single) As Integer

End Interface

当一个类使用Implement关键字来执行利用重载方法的界面的时候，类必须执行每一个重载每一个重载方法声明。


(十二)

VB.NET面向对象的实现(十二)
编译：ZSC/太平洋网络学院

界面

执行界面

就象在VB6中，执行一个界面是通过使用Implements关键字来实现的：

Public Class TheClass

Implements MyInterface

End Class

但是在VB6和VB.NET中还是有点区别的。在VB6中，我们执行不同的界面元素是设置为Private方法的。这些方法不直观并且容易使程序员感到困惑。而在VB.NET提供了一个清晰的、简便的语法来执行界面，它的实现是通过应用Implements关键字来完成的。

我们可以在类中简单地标记一个方法作为界面中的特殊方法的执行：

Public Sub MyMethod() Implements MyInterface.MyMethod

这样为了执行我们本例子的界面，我们必须编写以下代码：

Public Class TheClass

Implements MyInterface

Public Event MyEvent() Implements MyInterface.MyEvent

Public Function MyFunction(ByVal Param1 As Integer) _

As System.Integer Implements OOlib.MyInterface.MyFunction

End Function

Public Sub MyMethod() Implements OOlib.MyInterface.MyMethod

End Sub

Public Property MyProperty() As String _

Implements OOlib.MyInterface.MyProperty

Get

End Get

Set

End Set

End Property

End Class

不象在VB6中，当我们执行界面的时候，我们必须执行界面中的所有元素，包括事件、方法以及属性等等。我们可以通过这个界面来创建客户代码以处理我们的对象：

Dim obj As MyInterface

obj = New Implementer()

obj.MyMethod

而VB6中执行界面中的一个方法需要编写如下的代码：

Private Sub MyInterface_MyMethod()

（此处是执行的代码）

End Sub


(十三)

VB.NET面向对象的实现(十三)
编译：ZSC/太平洋网络学院

界面

执行多个界面

一个类中可以有多个执行语句，即执行多个界面。例子如下：

Public Interface MyInterface

Sub DoSomething()

End Interface

Public Interface OtherInterface

Sub DoWork()

End Interface

我们可以构造一个类来执行两个界面，代码如下：

Public Class TheClass

Implements MyInterface

Implements OtherInterface

End Class

接下来的例子，我们可以执行DoSomethind方法也可以执行DoWork方法：

Private Sub DoSomething() Implements MyInterface.DoSomething

（此处是执行的代码）

End Sub

Private Overloads Sub DoWork() Implements OtherInterface.DoWork

（此处是执行的代码）

End Sub

或者，如果以上两种方法是作同样的事情，我们可以利用一个方法来执行两个方法：

Private Sub DoSomething() _

Implements MyInterface.DoSomething, OtherInterface.DoWork

（此处是执行的代码）

End Sub

由上面的例子可以看出，我们可以在Implements关键字后用逗号分隔的列表类组合一系列的执行方法。


(十四)

VB.NET面向对象的实现(十四)
编译：ZSC/太平洋网络学院

对象的处理

VB.NET在声明、构造以及执行类上比VB6有很大的变化，同样在对象的处理上也有不小的改变。这些改变影响了我们实例化对象、引用和取消引用对象以及我们使用捆绑技术的方法。下面我们就开始详细说明吧。

对象声明和实例化

VB.NET没有使用CreateObject语句来创建对象。CreateObject是VB与COM密切相关的一个产物。因为VB.NET不再使用COM，所以从VB.NET开始就不在使用CreateObject。

New语句

VB.NET使用New语句来创建对象。我们可以使用New在代码的任何地方。下面的例子我们来创建一个变量并且在类的一个实例中创建一个对象的实例：

Dim obj As TheClass

obj = New TheClass()

我们可以简化上面的语句：

Dim obj As New TheClass()

VB6中以上的两段语句会存在一些事情，但是在VB.NET中上面的两段语句之间是没有什么区别的，只是第二段语句缩短了而已 。

下面我们要讲讲变量的作用域。如果你在一个块结构中声明一个变量，那个变量就只有在块结构中才有效。在许多情况下，我们想在方法的作用域中声明一个变量，或者想在在块结构（比如Try...End或者loop循环结构）中创建一个实例。在这样的情况下，用实例化来组合声明有点不妥。

上面的语句为我们定义了一个变量并实例化了一个类。这条语句可能在处理继承或者多个界面的时候会更有用。我们可以声明变量为其中一种类型并且基于要执行界面的类来实例化对象：

Dim obj As MyInterface = New TheClass()

我们可以同时利用更复杂的语句。假如我们有个需要对象引用的方法，我们可以这样来实例化对象：

DoSomething(New TheClass())

以上的语句是调用DoSomething方法并且传递TheClass的一个新的实例作为参数。这个新的对象就只有存在于这个方法的调用的事件内，即当方法完成之后，这个对象就自动被取消引用。

这里还得提醒一下，取消引用一个对象不是意味着马上终止这个对象。这一点我们在前面的教程中有作解释。对象只有在.NET的垃圾收集处理程序的时候才将它们从内存清除掉。

下面的例子可能更复杂。不是利用一个对象引用，我们的方法需要一个字符串。我们可以从一个方法提供一个字符串数值到我们的对象中来实例化对象并调用方法：

DoSomething(New TheClass().GetStringData())

很显然，我们需要仔细观察一下这条语句的可读性。语句的压缩往往较少了可读性，这点是我们应该注意到的。


(十五)

VB.NET面向对象的实现(十五)
编译：ZSC/太平洋网络学院

对象的处理

没有Set关键字

当我们处理对象的时候，我们没有使用Set语句。在VB6 中，处理对象引用的时候我们不得不使用Set命令处理来自其它数据类型的对象。而在VB.NET中来自其它数据类型的对象是采用不同的方法来处理的，这里我们可以使用直接的参数来处理对象，就象处理整型或者字符型数据类型。这个Set命令在VB.NET中不再有效。

取消引用对象

在VB6中，我们可以通过设置对象引用为Nothing(空)来取消引用对象。这点和VB.NET中的处理方法是一样的。

Dim obj As TheClass

obj = New TheClass()

obj = Nothing

但是在VB.NET中这条语句有不同的效果。因为VB.NET不是使用引用计算来终止对象，而是依靠垃圾收集机理。而在VB6中，当没有变量访问对象的引用，这个对象就被终止。在VB.NET中，以下这样看法是错误的：当垃圾收集处理程序发现对象没有被引用它就被终止。正确的应该是，在最后一个引用被移除之后的一段时间后才将对象从内存中清除。

但是这并没有清除被取消对象的数值。如果你有一个长时间运行的算法，那么你最好在处理程序中显式地取消引用这个对象，这样就可以在可能的情况下由垃圾收集程序清除它们。只要我们的代码保留了对象的引用，那对象就会保持在内存中而不会被垃圾收集程序清除。


(十六)

VB.NET面向对象的实现(十六)
编译：ZSC/太平洋网络学院

对象的处理

早的和晚的捆绑

VB的一个强大的功能是在处理对象的时候可以访问早的和晚的捆绑。你看完这句一定会觉得云里雾里的，好吧，下面就详细叙述一下早的和晚的捆绑吧。

所谓早的捆绑意思是说代码在直接处理对象时提前知道数据类型并且可以更有效的处理对象。早的捆绑允许IDE使用IntelliSense来提供开发效率，以及允许编译程序确保我们引用的方法存在并且提供正确的参数数值。

晚的捆绑的意思是代码动态地处理对象。这提供了更大的灵活性，因为代码没有考虑对象的类型，并且只要对象支持我们想要调用的方法，它就被处理。并且因为IDE或者编译程序不能识别对象的类型，而且没有IntelliSense和编译过程的语法检查，所以它将带来一些预想不到的灵活性。

VB.NET继承了这个传统，并且它在处理对象的时候提供了对早的和晚的捆绑的支持。

缺省状态下，所有的对象是早的捆绑。只要Option Strict 被设置On，IDE和编译器强迫这样作，On也是缺省的。但是，如果Option Strict 被设置Off，我们在整个代码中就使用晚的捆绑。

对象类型的使用

晚的捆绑发生在编译器不能判断对象的类型的时候。这个问题可以通过使用对象的数据类型类解决。一个数据类型对象的变量可以保留任何的数值，包括任何类型对象的引用。这样，如同下面的代码就可以在任何对象中运行以完成一个MyMethod方法，这个方法没有任何参数。

Option Strict Off

Module LateBind

Public Sub DoSomething(obj As Object)

obj.MyMethod()

End Sub

End Module

如果对象传递这个程序（没有一个无参数的MyMethod方法），那么就会出现一个错误。这里推荐，使用晚的捆绑的代码要总是提供错误俘获：

Option Strict Off

Module LateBind

Public Sub DoSomething(obj As Object)

Try

obj.MyMethod()

Catch

（这里可以进行一些适当的处理来给出调用这种方法的错误）

End Try

End Sub

End Module

虽然晚的捆绑比较灵活，但它容易导致错误并且比起早的捆绑更慢。为了产生晚的捆绑方法的调用，.NET程序必须动态地判断目标程序是否由一个方法来匹配我们调用的方法，并且它必须调用那个方法。这会比早的捆绑花更多的时间，因为早的捆绑能够提早知道方法的存在并且编译代码以使得调用变得很直接。


(十七)

VB.NET面向对象的实现(十七)
编译：ZSC/太平洋网络学院

对象的处理

晚的捆绑和反射

.NET框架支持反射的概念。反射是这样一种编写代码的能力，这些代码可以检查其它.NET代码并判断它们的组成。System.Reflection名空间支持反射。

反射允许我们编写代码来检查在方法、属性和时间的类，这些类应用于其它类中。我们可以使用反射来创建这些类的实例并调用这些方法。这个处理过程很象晚的捆绑，它们都是动态的。

实际上，VB.NET使用反射来执行晚的捆绑。VB.NET不是强迫我们编写代码来使用以发现和调用方法，它是在我们使用晚的捆绑编码技术的时候来发现和调用方法。

我们可以在VB6中使用typelib DLL(动态连接库)来执行一个反射受限的窗体。在DLL中的函数允许我们动态地发现在COM DLL中的类和方法，并且调用它们。

CType函数的使用

使用对象数据类型来传递对象引用并在我们需要处理它们的时候将它们转换为适当的类型是十分有用的。这一切可以通过使用Ctype函数来实现，它允许我们使用类型对象的变量来使用早的捆绑方法调用：

Module LateBind

Public Sub DoSomething(obj As Object)

CType(obj, TheClass).MyMethod()

End Sub

End Module

我们使用CType方法来暂时将变量转换为一个特殊的类型而不管TheClass的类型。Ctype函数是很有用的，特别是我们处理对象来执行多个界面的时候，因为我们可以引用一个对象变量并且它可以转换为适当的类型。举个例子，如果我们有一个类型的对象TheClass，这个对象执行MyInterface，那么我们可以这样来编写代码：

Dim obj As TheClass

obj = New TheClass

CType(obj, MyInterface).DoSomething()

不象VB6，我们可以在VB.NET中利用早的捆绑调用对象中的其它界面而不需要声明新的界面类型的变量。


(十八)

VB.NET面向对象的实现(十八)
编译：ZSC/太平洋网络学院

交叉语言的继承

VB.NET可以创建处理代码，这些处理代码是运行在.NET框架上的。所有的管理代码可以和其它类型的处理代码交互作用，而不管我们是用什么编程语言来创建这些组件的。这就意味着我们可以在一种编程语言上创建一个类，然后应用到另外的编程语言中，当然也包括继承。这正式交叉语言混继承的混合编程机理。

实际上，现在有许多程序涉及人员已经在应用这个技术了。许多的.NET系统类库是在C#上编写的，而我们在VB.NET上编写程序的时候，可以继承这些类作为基类。

创建VB.NET基类

举个例子，我们可以在VB.NET创建一个类库工程取名为vblib并且增加一个简单的类为Parent，代码如下：

Public Class Parent

Public Sub DoSomething()

MsgBox(Parent DoSomething, MsgBoxStyle.Information, Parent)

End Sub

End Class

利用这个基类我们可以在C#上创建一个子类。


(十八)

VB.NET面向对象的实现(十八)
编译：ZSC/太平洋网络学院

交叉语言的继承

创建C#子类

我们可以增加一个新类库工程，具体做法是使用菜单File（文件）->Add Project（增加工程）并将它命名为cslib。接着通过选择菜单Project（工程）->Add Reference（增加引用）来增加一个引用到vblib工程。

当我们在IDE中直接引用这个工程的时候，我们不需要VB.NET的源代码。相反地，我们可以先创建vblib工程，再创建一个组件，接着从C#工程中引用这个组件来得到访问基类的目的，代码如下：

namespace cslib

{

using System.WinForms;

using vblib;

public class csclass : Parent

{

public csclass()

{

Messagebox.Show(csclass constructor);

}

}

}

以上这个C#代码共享了VB.NET中的代码。但是，C#的语法很大程度上来自C和C++语言，所以编程会变得复杂一点。所有的代码语句的最后要以分号（；）结束，并且利用左右括号（{和}）来定义一个块结构。而在VB.NET中定义一个块结构是利用Sub...End Sub语句，这正是VB.NET和C#语法上的一个差别，所以在利用VB.NET和C#混合编程的时候一定要注意到语法的差别。

我们还是仔细体会体会上面的代码吧。代码的第一行是为文件定义了名空间（namespace）。在C#中所有的名空间是显式定义在每一个代码模块中的：

namespace cslib

在C#中的using关键字等价于在VB.NET中的Imports关键字。因为我们要使用System.WinForms和来自vblib的名空间，所以我们使用以下的语句来引入这些名空间：

using System.WinForms;

using vblib;

代码接下去的一行是声明我们要创建的类以及表明这个类是Parent的一个子类：

public class csclass : Parent

在C#中一个子类是通过定义一个类来定义的，具体语法是类名之后加冒号（：），然后再加基类。这条语句等价于如下VB.NET的代码：

Public Class csclass

Inherits Parent

在VB.NET中构造函数是通过使用保留的方法New来创建的。而在C#中构造函数是使用类名作为方法的名字来创建的，例如：

public csclass()

{

Messagebox.Show(csclass constructor);

}

在C#中，大括号（{和}）定义一个块结构，而在这个块结构中我们可以放置方法的代码。在这个例子中的方法很简单，只是显示一个对话框来指示构造函数被调用了而已。

至此我们就可以为新工程创建客户代码了。


(十八)

VB.NET面向对象的实现(十八)
编译：ZSC/太平洋网络学院

交叉语言的继承

创建客户应用程序

首先可以使用菜单File（文件）->Add Project（增加工程）来增加一个新的VB.NET 的Windows应用程序工程。在这个新工程可以选择菜单项Project（工程）->Add Reference（增加引用）来为cslib工程增加一个引用。在工程中点击鼠标右键并从弹出的菜单中选择Set As Startup Project选项，这样做的目的是当你按下F5快捷键的时候工程就运行。

这里值得注意的是，vblib工程没有任何的引用，这是因为我们没有直接使用来自组件的任何代码。所有的客户应用程序所关心的是cslib工程。

当我们在IDE中直接引用cslib工程的时候，我们不需要C#代码。相反地，我们可以先创建cslib工程，再创建一个组件，接着引用来自客户工程的组件以访问我们的测试C#类。

接着我们还要增加一个按钮到窗体中，并为该按钮编写以下的代码：

Protected Sub Button1_Click(ByVal sender As Object, _

ByVal e As System.EventArgs)

Dim obj As New cslib.csclass()

obj.DoSomething()

End Sub

虽然创建一个VB.NET的子类也是没什么差别的，但是在本例子中我们是使用了不同的编程语言来实现的。其中的差别大家仔细体会，相信会对你有所帮助。

好了，当我们运行应用程序并点击按钮的时候，我们就可以看到一个对话框，对话框上面显示了我们所调用的csclass的构造函数；以及另外一个对话框，其上面显示了我们所调用的VB.NET基类的DoSomething方法。


(十九)

VB.NET面向对象的实现(十九)
编译：ZSC/太平洋网络学院

可视化继承

上面的教程我们已经讨论了VB.NET新的面向对象的特性，其中很大一部分是在阐述继承。可能许多程序涉及人员还不知道VB.NET还支持Windows窗体的可视化继承。可视化继承，就是说我们可以创建一个Windows窗体，然后我们可以继承这个窗体使得其它窗体具有与该窗体相同的版面布置、控件和行为。
我们也可以使用继承来创建我们自己的Windows控件。比如，我们可以创建一个性能提高了的TextBox(文本框)来实现数据输入的特殊的有效性校验。具体的做法是：通过继承创建一个由原始文本框控件类继承而来的子类，并进行适当的修改以提高文本框的性能，使之可以实现对数据输入的有效性校验。
这一点跟Web表单控件是相同的，Web表单控件可以由一个已经存在的Web表单控件来创建一个子类。我们的子类可以重载已有的函数或者增加一些新的函数。

总结

至此“VB.NET面向对象的实现”教程就全部结束，有必要在这里作番总结。VB.NET不仅给我们提供了继承，而且还提供了其它许多重要的新特性。
VB.NET改进了我们创建和处理多界面的方法，使得我们可以更容易地使用它们。另外，VB.NET支持事件作为界面的一个部分，使得我们现在可以在界面上表达所有的元素：方法、属性、事件。
此外，在VB.NET中终止对象不是通过引用计数来实现，而是利用“垃圾收集”处理程序来将对象从内存中清除。
总而言之，VB.NET比起VB来说，其面向对象的能力大大增加了，而且VB.NET也保留了低版本绝大多数的特性。

[上一页]


酷站推荐

◎->露点美女秀 http://mnxiu.126.com 或 http://mnshow.myetang.com
简介：收集了超过1000M的中日明星写真照片及性感壁纸，张张都精彩！

◎->QQ贴图宝库 http://qqpic.126.com
简介：2000余款聊天室专用贴图，让你充满自信！

◎->中华特效王 http://cntxking.126.com
简介：1000余个网页特效代码 + 在线演示， 让你的主页动起来！新手不可错过哦^o*