VB默认属性、动态数组、Range对象的默认属性的一点不成熟的想法

1、默认属性

       VB6.0有默认属性的特性。当没有给对象指定具体的属性时,"默认属性"是VB6.0将使用的属性。在某些情形下,省略常用属性名,使代码更为精简。

       因为CommandButton的默认属性是Value,所以下面两句代码是等价的:

1 Sub Test()
2 Debug.Print UserForm1.CommandButton1     '输出Falue
3 Dim a
4 a = UserForm1.CommandButton1
5 Debug.Print a                            '输出False
6 End Sub

         而从F2对象浏览器中,可以看到Value确实是CommandButton的缺省成员(默认属性)——属性图标也和其它不同,左上角多了一个小圆圈。

      另一些情况,假如我们需要的是对象本身,而不是它的某个属性,比如我们想要把CommandButton1这个对象本身赋值给一个变量,就要使用Set “显式” 声明:

1 Sub Test()
2 Dim cmd As MSForms.CommandButton
3 Set cmd = UserForm1.CommandButton1
4 End Sub

      当一个对象不存在默认属性,获得对象本身是否需要使用set?答案是肯定的,将一个对象赋值给变量,必须使用Set关键字:Set a = Sheet1

2、动态数组Variant

     定义动态数组:(没有初始化长度)

      Dim arr() As Integer '元素为整型的动态数组 

      Dim brr() As Variant '元素为variant类型的动态数组 

      Dim crr() '元素为variant类型的动态数组 

      动态数组的特性之一:可被同一类型的静态数组初始化(赋值)

 1 Sub Test()
 2 Dim arr() As Integer
 3 Dim brr(1 To 3) As Integer    '静态数组
 4     brr(1) = 1
 5     brr(2) = 2
 6     brr(3) = 3
 7     arr = brr
 8 Dim crr() As Variant
 9 Dim drr(1 To 3) As Variant
10     drr(1) = 1
11     drr(2) = True
12     drr(3) = "张三"
13     crr = drr
14 End Sub

     如果静态数组和动态数组的元素类型不一致,则产生错误。下面的代码报编译错误“不能给数组赋值”。

1 Sub Test()
2 Dim arr()
3 Dim brr(1 To 3) As Integer
4     arr = brr                  '不能给数组赋值
5 End Sub

3、利用Range的Value属性和Variant()接收单元格区域的值

       Range是一个区域时,它的Value返回一个静态Variant(),而动态Variant()是可是接收这个返回值的。

1 Sub Test()
2 Dim arr()
3 arr = Range("A1:A5").Value
4 arr = ThisWorkbook.Worksheets(1).Range("A1:A5").Value
5 End Sub

      实际写VBA代码时,更多是像下面这样,使用variant变量达到相同效果:

1 Sub Test()
2 Dim arr
3     arr = Range("A1:A5")
4     arr = ThisWorkbook.Worksheets(1).Range("A1:A5")
5 End Sub

     这样的写法没有属性的显式调用,可能许多人会认为利用了Range对象的默认属性,这个默认属性会让人觉得是Value或Value2。

4、Range对象的默认属性是什么?

      入门VBA的时候,绝多数人都说Value是Range对象的默认属性,所以下面这样写,大多数人认为是省略Value的写法:

1 Sub Test()
2 Dim arr()
3        arr = Range("A1:A5")
4 End Sub

       而这个说法有可能是错的。实际上,可能_Default 才是Range的默认属性

      1、_Default属性两个参数都是可选的。意味着两个参数都可以没有。而这个属性的返回值没有定义,意味着它可以是Variant()或Variant。

      2、Range("A1")和Range("A1").Value,从截图中可猜测上例的情况并不是省略了Value的写法。

      3、_Default是Range对象的默认属性,而且是没有名字的。(仅仅是推测,可以有不取名字的属性么?)

推测证据1:

    [题外话:worksheets也有一个_Default默认属性,事实上,发现集合类对象几乎都有_Default默认属性(用作索引)。可自行求证] 

     下面这些写法是成立的:

Debug.Print Range("A1:A5")(2, 1)

Debug.Print Range("A1:A5")(1) 

推测证据2:

      我们常用Cells(index,index)的方式表示一个单元格。那这个表示法是从何而来呢?Cells属性本身并没有参数,见图:

       但Cells属性返回的是Range对象,Range对象的默认属性即_Default:

5Object类型和一个保留问题
     
使用默认属性常常会见到这样的问题:

      正常运行的代码A

1 Sub Test1()
2 Dim arr()
3     arr = Range("A1:A5")
4 End Sub

     正常运行的代码B :

1 Sub Test2()
2 Dim arr
3     arr = ThisWorkbook.Worksheets(1).Range("A1:A5")
4 End Sub

     运行会报错的代码C

1 Sub Test3()
2 Dim arr()
3     arr = ThisWorkbook.Worksheets(1).Range("A1:A5")
4 End Sub

      上面的写法均省略了默认属性。(是Value?   还是_Dafault?)

      B和C等式右边的表达式是完全相同的。但在运行时,arr可以正常赋值,arr()就会报错。

      需要留意的是,Worksheets(1)的类型是Object,不是一个强类型。arr()遇到Object.Range(),正是这种情况会出现问题,而不能正常解析的问题原因没找出。

     

     上面报错的代码,如果换一种方式,先声明一个显式类型Worksheet,问题就解决了。

1 Sub Test4()
2 Dim arr()
3 Dim sht As Worksheet
4     Set sht = ThisWorkbook.Worksheets(1)
5     arr = sht.Range("A1:A5")
6 End Sub

6、自定义类的默认属性 

      如何在自己类中定义默认属性呢?

      VB6实现:(一个对象只能有一个默认属性)

      步骤1:在写好属性过程后,然后点击工具—过程属性

     

     步骤2:在过程属性中,选择要设置为默认属性的名称,点选高级,最近设置过程标识符为“缺省”

     

   VBA实现:

   方法: 将类模块代码导出,使用文本编缉器(比如notepad)修改代码,然后重新导入VBA类模块。

   案例:写一个Person类,有一个属性叫P_name,现在想要设置它为Person类的默认属性。

 1 Private name As String
 2 
 3 Public Property Get P_name() As String
 4    P_name = name
 5 End Property
 6 
 7 Public Property Let P_name(ByVal vNewValue As String)
 8      name = vNewValue
 9 End Property
10 
11 Private Sub Class_Initialize()
12     name = "张三"
13 End Sub

    1、导出类文件到本地,默认文件名为:Person.cls
    2、使用文本编缉器打开。(文字涂灰的部分是自动生成的)
    3、修改属性过程代码,在P_name属性过程中添加一句:Attribute P_name.VB_UserMemId = 0
    4、将修改后的cls重新导入类模块。

 1 VERSION 1.0 CLASS
 2 BEGIN
 3   MultiUse = -1  'True
 4 END
 5 
 6 Attribute VB_Name = "Person"
 7 Attribute VB_GlobalNameSpace = False
 8 Attribute VB_Creatable = False
 9 Attribute VB_PredeclaredId = False
10 Attribute VB_Exposed = False
11 
12 
13 Private name As String
14 
15 Public Property Get P_name() As String
16    Attribute P_name.VB_UserMemId = 0
17    P_name = name
18 End Property
19 
20 Public Property Let P_name(ByVal vNewValue As String)
21      Attribute P_name.VB_UserMemId = 0
22      name = vNewValue
23 End Property
24 
25 Private Sub Class_Initialize()
26     name = "张三"
27 End Sub

      使用:

 1 Sub Test()
 2 Dim p As New Person
 3 
 4 Debug.Print p
 5 'Debug.Print p.P_name
 6 
 7 p = "李四"               '直接给对象赋值(实际赋值给了默认属性)
 8 Debug.Print p
 9 'Debug.Print p.P_name
10 
11 End Sub

 

posted @ 2016-12-08 21:51  复杂的石头  阅读(4166)  评论(0编辑  收藏  举报