【问题标题】:VBA "Compile Error: Statement invalid outside Type Block"VBA“编译错误:语句在类型块外无效”
【发布时间】:2015-09-08 08:23:12
【问题描述】:

我在 Excel 2010 中运行 VBA 宏,其中包含大量计算,因此数据类型非常重要,以尽可能缩短宏执行时间。

我的优化思路是让用户选择所有数字将被声明为什么数据类型(同时指出每种数据类型的优缺点,准确性/灵活性和 CPU 密集度/宏执行时间之间的平衡)。但是,当我运行宏时,我收到以下错误消息:

编译错误:

在类型块外声明无效

这里是代码的违规部分:

Ind2 As Double, BgrValP As Double, BgrRow As Double, M40eff As Double

这是宏的相关部分:

' Develop fake data to at glance recognize whether program works.
' Source http://www.cpearson.com/excel/optimize.htm
Option Explicit

Private Sub Function1()
On Error GoTo ErrorHandler
Dim userChoice As Variant
Dim strPath As String, strFileN As String, strDirN As String, strRangeNOut As String, strRangeNIn As String, strFilename As String, strTLCorn As String, strBRCorn As String, strSelectedFile As String, strtemp_name As String
Dim lngCount As Long
Dim vResMatrix(), vCPath, vFileN As Variant

'   MEeff = measure of efflux due to crudely purified HDL in scintillation
'   https://msdn.microsoft.com/en-us/library/ae55hdtk.aspx

'   Give the user macro options based on how fast or slow the computer is
userChoice = MsgBox("This macro by default treats all numbers as doubles for maximum precision. If you are running this macro on an old computer, you may want to redeclare numbers as singles, to speed up the macro." & vbNewLine & "You can also use integers for a quick estimate of data results.")

If userChoice = "Double" Then
    Dim RangeNOut As Double, vRangeNIn As Double, Ind6 As Double, Ind4 As Double, Ind5 As Double
    Dim Step2 As Double, MRow As Double, ColIn As Double, Ind3 As Double, Mcol As Double
    Dim MxRNo As Double, BgrSum As Double, RowIn As Double, Ind As Double, M40eff As Double, Step As Double
    Dim ColNo As Double, Startcol As Double, Startrow As Double, MeanComp As Double
    Dim PlateNo As Double, MonoVal As Double, Ind1 As Double, EntryRow2 As Double, EntryRow As Double
    Ind2 As Double, BgrValP As Double, BgrRow As Double, M40eff As Double
    Dim BrgSum As Double, BgrVal As Double, RangeNIn As Double, RangeNOut As Double, TLCorn As Double
    Dim Volcorr As Double, BRCorn As Double, MEeff As Double, MediaVal As Double

ElseIf userChoice = "Integer" Then
    Dim RangeNOut As Integer, vRangeNIn As Integer, ecInd6 As Integer, Ind4 As Integer, Ind5 As Integer
    Dim Step2 As Integer, MRow As Integer, ColIn As Integer, Ind3 As Integer, Mcol As Integer
    Dim MxRNo As Integer, BgrSum As Integer, RowIn As Integer, Ind As Integer, M40eff As Integer
    Dim Step As Integer, ColNo As Integer, Startcol As Integer, Startrow As Integer, MeanComp As Integer
    Dim PlateNo As Integer, MonoVal As Integer, Ind1 As Integer, EntryRow2 As Integer, EntryRow As Integer
    Dim Ind2 As Integer, BgrValP As Integer, BgrRow As Integer, M40eff As Integer
    Dim BrgSum As Integer, BgrVal As Integer, RangeNIn As Integer, RangeNOut As Integer, TLCorn As Integer
    Dim Volcorr As Integer, BRCorn As Integer, MEeff As Integer, MediaVal As Integer

ElseIf userChoice = "Single" Then
    Dim RangeNOut As Single, vRangeNIn As Single, ecInd6 As Single, Ind4 As Single, Ind5 As Single
    Step2 As Single, MRow As Single, ColIn As Single, Ind3 As Single, Mcol As Single
    Dim MxRNo As Single, BgrSum As Single, RowIn As Single, Ind As Single, M40eff As Single, Step As Single
    Dim ColNo As Single, Startcol As Single, Startrow As Single, MeanComp As Single
    Dim PlateNo As Single, MonoVal As Single, Ind1 As Single, EntryRow2 As Single, EntryRow As Single
    Ind2 As Single, BgrValP As Single, BgrRow As Single, M40eff As Single
    Dim BrgSum As Single, BgrVal As Single, RangeNIn As Single, RangeNOut As Single, TLCorn As Single
    Volcorr As Single, BRCorn As Single, MEeff As Single, MediaVal As Single

Else
    GoTo Function1
    MsgBox("This is not a supported data type: double, single, or integer.", vbCritical, "Unsupported Data Type")

这是我目前使用的代码:

Private Sub Function2(ByVal VarType As String)

Dim mVers As String
Dim userChoice As Variant

'   Give the user macro options based on how fast or slow the computer is using advanced conditional compliling
userChoice = MsgBox("This macro by default treats all numbers as doubles for maximum precision. If you are running this macro on an old computer, you may want to relare numbers as singles, to speed up the macro." & vbNewLine & "You can also use integers for a quick estimate of data results.")
userChoice = VarType

#If VarType = "Double" Or "double" Then
    Dim RangeNOut As Double, vRangeNIn As Double, Ind6 As Double, Ind4 As Double, Ind5 As Double
    Dim Step2 As Double, MRow As Double, ColIn As Double, Ind3 As Double, Mcol As Double
    Dim MxRNo As Double, BgrSum As Double, RowIn As Double, Ind As Double, M40eff As Double, Step As Double
    Dim ColNo As Double, Startcol As Double, Startrow As Double, MeanComp As Double
    Dim PlateNo As Double, MonoVal As Double, Ind1 As Double, EntryRow2 As Double, EntryRow As Double
    Dim Ind2 As Double, BgrValP As Double, BgrRow As Double, M40eff As Double
    Dim BrgSum As Double, BgrVal As Double, RangeNIn As Double, RangeNOut As Double, TLCorn As Double
    Dim Volcorr As Double, BRCorn As Double, MEeff As Double, MediaVal As Double
#ElseIf VarType = "Single" Or "single" Then
    Dim RangeNOut As Single, vRangeNIn As Single, ecInd6 As Single, Ind4 As Single, Ind5 As Single
    Step2 As Single, MRow As Single, ColIn As Single, Ind3 As Single, Mcol As Single
    Dim MxRNo As Single, BgrSum As Single, RowIn As Single, Ind As Single, M40eff As Single, Step As Single
    Dim ColNo As Single, Startcol As Single, Startrow As Single, MeanComp As Single
    Dim PlateNo As Single, MonoVal As Single, Ind1 As Single, EntryRow2 As Single, EntryRow As Single
    Dim Ind2 As Single, BgrValP As Single, BgrRow As Single, M40eff As Single
    Dim BrgSum As Single, BgrVal As Single, RangeNIn As Single, RangeNOut As Single, TLCorn As Single
    Dim Volcorr As Single, BRCorn As Single, MEeff As Single, MediaVal As Single
#ElseIf VarType = "Integer" Or "integer" Then
    Dim RangeNOut As Integer, vRangeNIn As Integer, ecInd6 As Integer, Ind4 As Integer, Ind5 As Integer
    Dim Step2 As Integer, MRow As Integer, ColIn As Integer, Ind3 As Integer, Mcol As Integer
    Dim MxRNo As Integer, BgrSum As Integer, RowIn As Integer, Ind As Integer, M40eff As Integer
    Dim Step As Integer, ColNo As Integer, Startcol As Integer, Startrow As Integer, MeanComp As Integer
    Dim PlateNo As Integer, MonoVal As Integer, Ind1 As Integer, EntryRow2 As Integer, EntryRow As Integer
    Dim Ind2 As Integer, BgrValP As Integer, BgrRow As Integer, M40eff As Integer
    Dim BrgSum As Integer, BgrVal As Integer, RangeNIn As Integer, RangeNOut As Integer, TLCorn As Integer
    Dim Volcorr As Integer, BRCorn As Integer, MEeff As Integer, MediaVal As Integer
#Else
    MsgBox "VarType " & VarType & " is not valid. Check spelling."
#End If

'   MEeff = measure of efflux due to crudely purified HDL in scintillation
MsgBox "For additional information about this macro:" & vbNewLine & "1. Go to tab Developer" & vbNewLine & "2. Select Visual Basic or Macro." & vbNewLine & "See the comments or MsgBoxes (message boxes)."

'   Start File Explorer to select file containing data (simple GUI, much easier than coding in the file)

With Application.FileDialog(msoFileDialogOpen)
    .AllowMultiSelect = True
    .Show

'   Display paths of each file selected
    For lngCount = 1 To .SelectedItems.Count
    Next lngCount
    For Each strFilename In .SelectedItems
        MsgBox strFilename
        Function2
    Next
End With

ErrorHandler:
MsgBox "Error detected" & vbNewLine & "Error" & Err.Number & ": " & Err.Description, vbCritical, "Error Handler: Error " & Err.Number
MsgBox "If you want to force the program to run, go to the line below and insert a ' mark to comment the line out." & vbNewLine & "On Error GoTo ErrorHandler", vbCritical, "Error Handler: Error " & Err.Number

End Sub

【问题讨论】:

    标签: vba excel excel-2010


    【解决方案1】:

    你有:

    Dim RangeNOut as Double
    Dim RangeNOut as Integer
    

    虽然其中的IF 语句是个好主意,但VBA 不允许您这样做。它不进行有条件的“编译”,因为它不是一种编译语言。当 VBA 运行您的代码时,您的所有变量都被声明(无论Dim 语句位于代码中的哪个位置),然后代码开始执行。

    这是您提出的一个好主意,但在 VBA 中尝试此操作就像将一块 Silly Putty™ 带入枪战 - 它非常不适合这项工作。

    此外,如果您担心执行速度,VBA 也不是您的首选武器。我没有任何统计数据可以支持它,但我怀疑您是否真的会根据三种不同的变量类型看到执行速度的很大差异。

    要将变量类型作为参数传递给函数,请使用:

    Private Sub Function1(ByVal VarType as String)
    
      #If VarType = "Double" then
        ...
      #ELSEIF VarType = "Single" then
        ...
      #ELSEIF VarType = "Integer" then
        ...
      #ELSE
        MsgBox "You passed in a 'VarType' of " & VarType & " - that's not valid"
      #ENDIF
    

    另外,我刚刚注意到在你的最终Else 中你有Goto Function1。我不确定你想在那里完成什么,但是:

    1. 不要使用goto。除了在 VBA 风格的错误处理中,几乎从不需要
    2. 无论如何,您没有为 Goto 定义要跳转到的标签。

    另请参阅VBA function overloading 以了解另一种可能的选择。

    注意:尽管有赞成票和接受的答案状态,但我尝试了以下操作,但它按 OP 的要求工作:

    Sub test()
      func "Double"
      func "Single"
      func "Integer"
      func "String"
    End Sub
    
    Function func(v As String)
      #If v = "Double" Then
        Dim myvar As Double
        Range("A1") = "MyVar type is: " & vartype(v)
      #ElseIf v = "Single" Then
        Dim myvar As Single
        Range("a2") = "MyVar type is: " & vartype(v)
      #ElseIf v = "Integer" Then
        Dim myvar As Integer
        Range("a3") = "MyVar type is: " & vartype(v)
      #Else
        Range("A4") = "Invalid var type passed: " & v
      #End If
    
      MsgBox "Passed in " & v
    
    End Function
    

    Func() 的所有调用最终都在代码的#Else 部分中,用Invalid var type passed: 文本填充Range("A4")

    很遗憾,这行不通。

    如果真的有必要让具有不同变量类型的函数做完全相同的事情,我认为以下是最好的选择:

    Sub Test()
      Dim VType as String
    
      While Vtype <> "Integer" and VType <> "Double" and VType <> "Single" and VType <> "Cancel"
        vType = msgBox("Enter variable type")
      Wend
    
      If VType = "Integer" then
        MyFuncInt()
      ElseIf VType = "Double" then
        MyFuncDouble()
      Elseif VType = "Single"
        MyFuncSingle()
      Else
        MsgBox "Function call cancelled"
      End if
    End Sub
    
    Function MyFuncInt()
      Dim AllTheVars as Integer
      ...
    End Function
    
    Function MyFuncDouble()
      Dim AllTheVars as Double
      ...
    End Function
    
    Function MyFuncSingle()
      Dim AllTheVars as Single
      ...
    End Function
    

    【讨论】:

    • 但是...#If [bool] Then
    • 实际上,VBA 已编译(某种程度上)并且确实支持conditional compilation。在运行时根据用户输入进行更改非常困难。
    • 同意。如果一切都是双倍的,数以万计的计算可能只会延迟你两三秒。测试它的最好方法是用三个不同的子程序编写它,为每种类型测试它,并计算编译需要多长时间。我也很想知道结果。
    • 好吧,who knew VBA 支持编译器指令!?!?!可以按照OP想要处理的方式完成吗?
    • 我看到它们被用来检查代码是否在 Mac 上运行:stackoverflow.com/questions/30990025/…。我同意,只要它们不是Variant,它的影响应该很小,这可能会有所作为。更大的问题是,以这种方式更改声明会对下游操作产生有意义的影响:Integer 的相等性测试是合理的,但对于浮点类型则不然。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    相关资源
    最近更新 更多