VBA中的变体数据类型及其正面使用

时间:2016-06-17 17:01:11

标签: excel-vba vba excel

Google上有关于变体数据类型的大量内容。大多数情况下,他们会说"Avoid using it too much and here's why""It can hold any type of data"之类的内容,这些都是我理解的内容。但我还是不完全明白何时使用它们。有人可以简明扼要地解释一下,更重要的是,给出变量数据类型的最佳用法示例(甚至可能是将变量传递给函数而不是显式声明变量的示例)?

3 个答案:

答案 0 :(得分:5)

通常,始终使用最小的内存变量。 Variant是最大的,所以你应该只在没有更好的类型时使用它。以下是一些例子

<强>阵列()

Array函数返回包含数组的变体。您可以使用Array的唯一方法是分配变体。

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

将阵列分配到范围

如果你必须将一堆数据写入单元格,那么将它们放入数组中并将它们全部写入而不是一次写入一个单元格会更快。如果您的数据都是相同的数据类型,请使用正确类型的数组。但如果不是所有相同的数据,您可能需要使用变量数组。

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

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

工作表函数

某些(所有?)工作表函数可以返回错误以及它们的正常值。唯一可以容纳的数据类型,例如Double和Error是Variant。

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

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

答案 1 :(得分:2)

Variant类型在内存中占用的空间比任何其他变量(here you'll find the code for the macro都多,为了测试,我只是添加了变体的例程)

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

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单独可以&#39;阻止,你应该做什么?

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。如果您不想添加正确的引用以避免late or early binding但是,您知道变量本身允许这些函数,这也有助于避免将来可能需要做的一些变通方法相关迟到,早期约束(虽然如果我这样做,我还没有遇到问题):

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


3。可以包含大量数据并且您希望控制它们的数组

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。元素中的元素,您还没有找到正确调用它们的方法,您将在以后学习或者不会对与调用它们的正确方法相关的性能产生影响。

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


大多数程序员不喜欢这种方法,因为你让Excel处理事情&#34;一个好的编码实践是你应该把所有内容都定义为OOP定义,但是,我发现在这方面做得非常好,加快了解决方案的速度,并为我们节省了一些.class /接口,然后再回到主要类别,我们将不得不在{{{ 3}}编程。作为OT:我的意思是,如果我们想要达到这个严格要求,我们需要在MVP中编程以避免编译器干扰我们的初衷。

答案 2 :(得分:0)

  

“...将变量传递给函数而不是显式声明的变量”

的示例

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

例如,看看这个将工作表添加到工作簿的宏:

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参数接受字符串或字符串数​​组,所以以下两个调用都是有效的:

'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”等)强制单个方法接受单个参数的多种数据类型,可以避免必须创建单独的方法完成类似的任务(即添加一个WS的“addSheet”,添加多个的“addSheets”)。