关于excel:VBA中的Variant数据类型及其积极用途

Variant data type in VBA and positive uses of it

Google上有很多关于变体数据类型的东西。 我通常会说"Avoid using it too much and here's why""It can hold any type of data"之类的东西。 但是我仍然不完全了解何时使用它们。 有人可以简要地解释一下,更重要的是,举例说明变量数据类型的最佳用法(甚至可以是将变量传递给函数而不是显式声明的变量的例子)?


通常,请始终使用您可以使用的最小内存变量。变体是最大的,因此,只有在没有更好类型的变体时才应使用它。这里有些例子

Array()

Array函数返回包含数组的变量。可以使用Array的唯一方法是将其分配给变量。

1
vArr = Array(1,"a", True)

将数组分配给范围

如果必须将一堆数据写入单元格,则将它们放入数组并一次全部写入而不是一次写入一个单元的方法要快得多。如果您的数据都是相同的数据类型,请使用正确类型的数组。但是,如果不是全部相同的数据,则可能需要使用一组Variants。

1
2
3
4
5
6
7
8
Dim vaWrite(1 To 2, 1 To 2) As Variant

vaWrite(1, 1) = 1
vaWrite(1, 2) ="Bob"
vaWrite(2, 1) = 2
vaWrite(2, 2) ="Tim"

Range("A1").Resize(2, 2).Value = vaWrite

换一种方式-范围到数组需要一个Variant,而不管单元中的数据类型如何

1
vArr = Range("A1:C10").Value

工作表功能

一些(全部?)工作表函数可以返回错误以及它们的正常值。可以保存例如Double和Error的唯一数据类型是Variant。

1
vRes = Application.WorksheetFunction.Match(...)

这是我能想到的三个例子。可能还有更多。


变量类型比任何其他变量占用更多的内存空间(在这里,您将找到宏的代码进行测试,我只是为变量添加了例程)

enter image description here
可能还有其他一些因素在起作用,这是一个非常主观的话题,因为这是我的个人经验:
1.一个好的代码必须被明确地解释,使用variant可能导致首先应该定义的内容混乱。
2.变体可能无法获得对象的真实属性,因此,它将花费更多时间进行编码,并且您可能看不到对象IE的真实属性:

1
2
3
4
5
6
Dim myRange as Range
Set myRange = Range("A1:A10")
myRange. 'I can see the properties of the object!
Dim myRange as Variant
Set myRange = Range("A1:A10")
myRange. 'I can't see what properties this may have in this context!

我想就为什么避免使用它们提供真实的背景-我认为我们都同意这一点-。
现在,何时使用它们?好吧,这可能也需要讨论,但是,当您无法控制输入时,我发现它们很有用。
这怎么可能发生?
示例1:一个TextBox值让用户输入,而我不想让用户键入单词,只能输入数字(无论何时键入单词都应阻止它),但是仅TextBox不能阻止它,所以,应该做?

1
2
3
4
5
6
7
8
9
10
11
12
Private Sub TextBox_Value_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Dim ChrPressed As Variant
    ChrPressed = Chr(KeyAscii)
    Select Case ChrPressed
        Case IsNumeric(ChrPressed)
        Me.TextBox_Value.Value = Me.TextBox_Value.Value & ChrPressed
        KeyAscii = 0
        Case"0"
        Me.TextBox_Value.Value = Me.TextBox_Value.Value & ChrPressed
        KeyAscii = 0
    End Select
End Sub

ChrPressed是Variant的地方,因为用户仍然可以按下单词键,但是我们将定义所按下的内容并在代码内部进行研究-其他方法可能会导致错误调试器给用户,使我们的体验变得不那么顺畅。
2.如果您不想添加适当的引用以避免后期绑定或早期绑定,但是您知道变量本身允许使用这些函数,那么这也有助于避免将来可能需要执行的一些变通方法迟了,早绑定了(尽管我没有那样做,但是我没有遇到任何问题):

1
2
3
4
Sub ImportFile()
Dim MyFile As Variant
MyFile = Application.GetOpenFilename("Import File*.CSV", Title:="CSV Data")
    If MyFile = False ...

3.可以包含大量数据的数组,而您想这样控制它们

1
2
3
4
Dim ArrayForTest() as Variant
Select Case ArrayForTest(ArrayElement)
Case IsNumeric(ArrayForTest(ArrayElement))
Case IsString(ArrayForTest(ArrayElement)) 'Just representative not the real way to do so

4.元素中的元素您没有找到正确调用它们的方法,以后您将学习或不会真正影响与正确调用它们的方法相关的性能。

1
2
3
4
Sub Graphs_makegraph(XValues As Variant, ChartStyle...
ActiveSheet.Shapes.AddChart2(ChartTypeNumber, ChartStyle).Select
...
ActiveChart.FullSeriesCollection(1).XValues = XValues

大多数程序员不喜欢这种方法,因为您是让Excel"处理问题",一种好的编码实践是应将所有内容都定义为OOP定义,但是,我发现这样做的卓越多功能性可以加快解决方案的速度,为我们节省一些.class / interfaces,然后再次返回到调用的主类,我们将不得不在MVP编程中执行其他操作。作为OT:我的意思是,如果要严格一点,就需要使用asm语言编程,以避免编译器的任何干扰,这是我们的初衷。


"...an example of passing a variant to a function as opposed to an explicitly declared variable"

Joel Spolsky在这里提到了这种形式的一种形式,但是我发现通过使用Variant类型的参数来模拟方法重载非常有用。

例如,看一下将工作表添加到工作簿的此宏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Sub addSheets(wb As Workbook, ByVal wsNames As Variant)
'Adds one or more worksheets (wsNames) to a workbook (wb)

    Dim ws As Worksheet
    Dim i As Long

    If Not IsArray(wsNames) Then
        wsNames = Array(wsNames)
    End If

    For Each ws In wb.Sheets
        For i = LBound(wsNames) To UBound(wsNames)
            If ws.Name = wsNames(i) Then
                MsgBox"Error: Sheet" & wsNames(i) &" already exists in workbook"
                Stop
                Exit Sub
            End If
        Next
    Next

    For i = LBound(wsNames) To UBound(wsNames)
        Dim newWS As Worksheet
        Set newWS = wb.Worksheets.Add
        newWS.Name = wsNames(i)
    Next

End Sub

因为它将接受wsNames参数的字符串或字符串数组,所以以下两个调用均有效:

1
2
3
4
'Adds sheet called"TestWS1" to the active workbook
Call addSheets(ActiveWorkbook,"TestWS1")
'Adds sheets called"TestWS2" and"TestWS3" to the active workbook
Call addSheets(ActiveWorkbook, Array("TestWS2","TestWS3"))

通过使用变体和" IsArray"方法(以及类似的方法,例如" IsNumeric"," IsDate"等)来强制单个方法接受单个参数的多种数据类型,您可以避免必须创建单独的方法来完成相似的操作 任务(例如," addSheet"用于添加一个WS," addSheets"用于添加多个WS)。