运用属性过程

Visual Basic 提供下表所列的三种属性过程。

过程 目的
Property Get 返回属性的值
Property Let 设置属性的值
Property Set 设置对象属性的值(即,该属性含有对象引用)。

从上表可见,每一个属性过程都有自己特殊的功能。典型的属性由一对属性过程组成:Property Get 检索属性的值,Property Let 或 Property Set 给属性赋值。

这些作用在有些情况下可能重叠。有两类赋值的属性过程的原因,是因为将对象引用赋给对象变量时,Visual Basic 有特殊的语法:

Dim wdg As Widget
Set wdg = New Widget

规则很简单:如果有 Set 语句,则 Visual Basic 调用 Property Set,如果没有则调用 Property Let。

提示   返回到经典的 Basics 语法,为了正确使用 Property Let 和 Property Set 保持清洁整齐,应键入 Let x = 4(直到今天 Visual Basic 还支持的语法)而不是 x = 4,。Visual Basic总是根据赋值类型决定调用属性过程— 对于 Let x = 4 调用 Property Let,对于 Set c1 = New Class1(对象属性)则调用 Property Set。

详细信息   “编程基础”中“对象使用”解释 Set 语句对对象变量的使用。

读写属性

下列编码显示了典型的读写属性:

'属性值的私有存储区。
Private mintNumberOfTeeth As Integer

Public Property Get NumberOfTeeth() As Integer
   NumberOfTeeth = mintNumberOfTeeth
End Property

Public Property Let NumberOfTeeth(ByVal NewValue _
   As Integer)
   '(省略验证属性值代码。)
   mintNumberOfTeeth = NewValue
End Property

存储了属性值的私有变量名,由作用域前缀 (m),类型前缀 (int) 和名称 (NumberOfTeeth) 组成,其中,作用域前缀 (m) 指明变量是模块级的。使用属性相同的名称可指明该变量和属性是相关的。

毫无疑问,已经注意到,这里和以前的示例一样,含有读写属性的属性过程名必须是相同的。

注意   属性过程缺省为公共的,因此,如果省略 Public 关键词,则属性过程仍是公共的。如果想要使属性为私有(只有对象内部才可访问),必须用 Private 关键词声明。即使不是必须,最好还是使用 Public 关键词,因为这可使意图清楚。

运行和播放属性过程

单步运行一些属性过程代码是有益处的。使用“工程”菜单,打开一个新的 Standard Exe 工程,并增添一个类模块。如上所示,从 NumberOfTeeth 属性复制代码到 Class1。

切换到 Form1,将下列代码添加到 Load 事件中:

Private Sub Form_Load()
   Dim c1 As Class1
   Set c1 = New Class1
   '赋给新的属性值。
   c1.NumberOfTeeth = 42
   '显示属性值。
   MsgBox c1.NumberOfTeeth
End Sub

F8 键,单步运行代码。注意,当属性被赋值时,运行跳到 Property Let,当检索属性值时,运行跳到 Property Get。将会发现,对属性过程其它组合,重复做这种练习是很有用的。

属性过程对的参数必须匹配

至今所见的属性过程示例都很简单,对多数属性而言属性过程也将是这样。但是,属性过程可有多个参数— 甚至可选参数。多个参数中最有用的是数组,下面将讨论。

当使用多个参数时,属性过程对的参数必须匹配。下表给出了在属性过程声明中参数的要求。

过程 声明语法
Property Get Property Get propertyname(1,..., n) As type
Property Let Property Let propertyname(1,..., n, n+1)
Property Set Property Set propertyname(1,..., n, n+1)

在 Property 过程中,从第一个参数到倒数第二个参数 (1,..., n),必须具有与过程相同的名称和数据类型。就象其它过程类型一样,列表中必需参数应排在第一个可选参数之前。

可能注意到,Property Get 过程的声明比相关的 Property Let 或 Property Set少一个参数。Property Get 过程的数据类型的声明必须与 Property Let 或 Property Set 最后一个参数 (n+1) 的数据类型一样。

例如,一个类似二维数组的属性的 Property Let 声明:

Public Property Let Things(ByVal X As Integer, _
ByVal Y As Integer, ByVal Thing As Variant)
   '(省略给数组元素赋值的代码。)
End Property

Property Get 的参数声明必须与 Property Let 过程的参数名称和数据类型相同:

Public Property Get Things(ByVal X As Integer, _
ByVal Y As Integer) As Variant
   '(省略从数组取值的代码。)
End Property

在 Property Set 声明中的最后参数的数据类型,要么是对象类型,要么是Variant 类型。

参数匹配

图 9.8 给出了这些参数匹配规则的理由。并显示了 Visual Basic 如何将赋值语句部分与 Property Let 参数相匹配。

图 9.8   Property Let 过程的调用

带多参数的属性过程最常用于创建属性数组。

只读属性

要创建只读属性,只须简单地省略 Property Let 或(对于对象属性)Property Set。

对象属性

若要创建一个读写对象属性,应使用 Property Get 和 Property Set 如:

Private mwdgWidget As Widget

Public Property Get Widget() As Widget
   'Set 语句被用来返回一个对象引用。
   Set Widget = mwdgWidget
End Property

Public Property Set Widget(ByVal NewWidget As Widget)
   Set mwdgWidget = NewWidget
End Property

 Variants 属性

 Variants 数据类型的读写属性是最复杂的。如下所示,使用三种属性过程类型:

Private mvntAnything As Variant

Public Property Get Anything() As Variant
   'Set 语句只用于包含了对象引用的任何属性。
   If IsObject(mvntAnything) Then
      Set Anything = mvntAnything
   Else
      Anything = mvntAnything
   End If
End Property

Public Property Let Anything(ByVal NewValue As Variant)
   '(省略验证代码。)
   mvntAnything = NewWidget
End Property

Public Property Set Anything(ByVal NewValue As Variant)
   '(省略验证代码。)
   Set mvntAnything = NewWidget
End Property

在正确环境中,Property Set 和 Property Let 总是很正常的使用。但是,使用 Property Get 必须考虑以下二种情况:

strSomeString = objvar1.Anything
Set objvar2 = objvar1.Anything

在第一种情况中,Anything 属性包含了字符串,它赋给了 String 变量。在第二个情况中,Anything 属性包含了对象引用,它被赋给对象变量。

通过使用 IsObject 函数,在返回值之前测试私有 Variants 变量,可对 Property Get 进行编程来处理这两种情况。

自然,当属性包含对象引用时,如果第一条编码被调用,将会出现错误,但这不是 Property Get 问题,而是使用 Variants 属性的问题。

仅写一次属性

属性过程有几种可能的组合。所有的组合都是有效的,但有些相对来说不太常用,比如只写属性(只有 Property Let,而无 Property Get)。有些则取决于另外的因素,而不是所组合的属性过程类型。

例如,如本章后“对象模型”所描述的那样,当通过创建一个对象模型在程序中组织对象时,可能想让该对象能引用包含它的对象。使用 Parent 属性可这样做。

当对象创建时,应设置 Parent 属性,但此后,可能想防止其被有意或无意地改变。以下示例显示了 Account 对象如何使用 Parent 属性。该属性指向含有帐号的 Department 对象。

'Parent 属性要用私有数据存储
Private mdeptParent As Department

Property Get Parent() As Department
   '使用 Set 语句引用对象。
   Set Parent = mdeptParent
End Property

'属性值只能被设置一次。
Public Property Set Parent(ByVal NewParent _
As Department)
   If deptParent Is Nothing Then
      '赋初值。
      Set mdeptParent = NewParent
   Else
      Err.Raise Number:=vbObjectError + 32144, _
      Description:="Parent property is read-only"
   End If
End Property

当访问 Account 对象的父对象时,例如通过代码 strX = acctNew.Parent.Name 获取部门名称,Property Get 被用于返回对父对象的引用。

该示例中,编入 Property Set 是为了使 Parent 属性只能被设置一次。例如,当 Department 对象创建一个新的帐号时,可以执行代码 Set acctNew.Parent = Me 设置属性。此后,该属性为只读的。

详细信息   因为在 Visual Basic 中窗体是类,故可向窗体添加用户属性。请参阅本章前面“定制窗体类”的内容。