【问题标题】:VBA: Expected Array Error despite No ArraysVBA:尽管没有数组,但预期的数组错误
【发布时间】:2019-07-13 08:10:05
【问题描述】:

在我用 VBA 制作的子程序中,每次工作表更改时都会执行该子程序,子程序调用一个函数来确定用户是否删除或更改了他们不应该拥有的东西。该函数返回一个布尔值来告诉 sub 是否已删除/编辑了这样的临界值。这样子就知道不继续执行代码了。

但是,无论何时执行代码,VBA 都会为调用 criticalDataIntact() 函数返回一个 Compile Error: Expected array 错误,尽管没有使用任何数组。

这是我的相关代码,

Private Sub Worksheet_Change(ByVal target As Range)
    Worksheets(CONFIG).usedRange 'Refresh UsedRange
    Dim criticalDataIntact As Boolean: criticalDataIntact = criticalDataIntact()

    If Not criticalDataIntact Then
        Exit Sub
    End If

    'Irrelevant code
End Sub

Private Function criticalDataIntact() As Boolean
    Dim criticalDataIntact As Boolean: criticalDataIntact = True
    Set warnWorkloadCell = ThisWorkbook.cell(CONFIG, WARNING_WORKLOAD, 0, 0)
    Set dangerWorkloadCell = ThisWorkbook.cell(CONFIG, DANGER_WORKLOAD, 0, 0)
    Dim table3Exists As Boolean: table3Exists = tableExists("Table3")

    If warnWorkloadCell = Null Or dangerWorkloadCell = Null Or table3Exists = False Then
        criticalDataIntact = False
    End If
End Function

cell 函数通过MsgBox 输出错误消息,如果在特定工作表中找不到具有特定值的单元格,则返回Null

有什么想法吗?

【问题讨论】:

  • 为什么要声明一个与它所在的函数同名的变量?
  • @K.Davis 在 VBA 中返回值不是这样吗?我尝试使用Return 关键字,但出现Expected: end of statement 错误。根据stackoverflow.com/questions/2781689/… 上的 Dan 所说,我的做法是正确的。
  • 没有。您已经将带有签名criticalDataIntact() 的返回类型声明为布尔值。如果您希望函数内部的局部布尔变量使用不同的名称,那么最后有criticalDataIntact = localBoolean ...。但我认为您可以简单地将上面的内容转换为criticalDataIntact = not(c1 = Null Or c2 = Null Or c3 = False)并且不需要 loca 变量
  • 补充 QHarr 的评论:VBA 不使用return 将函数结果传递回调用过程。这是一种 .NET 框架做事的方式 (VB.NET)。相反,您将函数的名称设置为要在函数代码末尾传回(返回)的结果。与 QHarr 的最后一句话相反,我更喜欢/推荐一个局部变量并在最后传回。这更清晰,更不容易出错(在我看来)。

标签: arrays excel vba


【解决方案1】:
  • 考虑将您的 CriticalDataIntact 函数重命名为 IsCriticalDataIntact
  • 如果您的Worksheets(CONFIG) 工作表与包含Worksheet_Change 代码的工作表相同,请考虑将Worksheets(CONFIG) 替换为Me
  • 如果您没有在 Worksheet_Change 子例程中的任何其他位置(即“无关代码”中的任何位置)引用您的 criticalDataIntact 变量,请考虑删除该变量并直接使用返回值。

根据上述情况,您的 Worksheet_Change 例程可能类似于:

Private Sub Worksheet_Change(ByVal target As Range)
    Worksheets(CONFIG).UsedRange ' Doesn't this give you a syntax error? If this is the same worksheet as the worksheet storing this procedure, consider using Me.UsedRange -- although maybe there a better alternatives to UsedRange.

    If Not IsCriticalDataIntact() Then
        Exit Sub
    End If

    'Irrelevant code
End Sub
  • 考虑模块顶部的Option Explicit。我这样说是因为您的 CriticalDataIntact 函数包含看似未声明的变量:warnWorkloadCelldangerWorkloadCell(除非这些是非局部变量)。

  • 我无权访问您的自定义函数cell,但假定它是您的ThisWorkbook 的成员。考虑将名称 cell 更改为更具描述性的名称

  • 关于cell 函数的返回类型,您说过它返回RangeNull。这听起来像是Variant 的行为(我的理解是只有Variants 可以在VBA 中存储Null)。但我认为这会导致调用站点的语法无效,因为您不能将SetVariant 转换为Null(据我所知)。
  • 听起来您想要的是返回类型为Range——如果无法返回Range,则将返回Nothing(您仍然可以对其进行测试)。
  • 根据上述情况,您的自定义函数cell 的更好名称可能是GetCellOrNothing

所以你的函数可能看起来像:

Private Function IsCriticalDataIntact() As Boolean

    Dim warnWorkloadCell As Range ' Declare if a local variable.
    Set warnWorkloadCell = ThisWorkbook.cell(CONFIG, WARNING_WORKLOAD, 0, 0) ' Consider renaming to "GetCellOrNothing" -- depending on how much work that is for you.

    Dim dangerWorkloadCell As Range ' Declare if a local variable.
    Set dangerWorkloadCell = ThisWorkbook.cell(CONFIG, DANGER_WORKLOAD, 0, 0) ' Consider renaming to "GetCellOrNothing" -- depending on how much work that is for you.

    Dim table3Exists As Boolean
    table3Exists = tableExists("Table3")

    IsCriticalDataIntact = table3Exists And Not ((warnWorkloadCell Is Nothing) Or (dangerWorkloadCell Is Nothing)) 

End Function

未经测试。

【讨论】:

    【解决方案2】:

    删除criticalDataIntact 之后的() 否则你说criticalDataIntact = 变体变量,因为criticalDataIntact() 是一个名为criticalDataIntact 的隐式变体变量。那是你错误的根源。

    Dim criticalDataIntact As Boolean: cIntact = criticalDataIntact '<remove the () which is implicit variant
    

    然后为了避免混淆编译器,使用不同命名的变量来保存返回值

    Dim cIntact As Boolean: cIntact = criticalDataIntact
    

    这个

    If warnWorkloadCell = Null Or dangerWorkloadCell = Null Or table3Exists = False Then
        criticalDataIntact = False
    End If
    

    可以变成

    criticalDataIntact = Not (IsNull(warnWorkloadCell) Or IsNull(dangerWorkloadCell) Or table3Exists = False)
    

    并消除对本地布尔值的需求。就个人而言,我会将 table3Exists 更改为 tableNotExists 并在该函数内进行必要的更改,以便我可以这样做

    criticalDataIntact = Not (IsNull(warnWorkloadCell) Or IsNull(dangerWorkloadCell) Or table3NotExists)
    

    我看不到您的单元格方法,所以我不知道它返回了什么,但对于对象,我通常会执行 If Not x Is NothingIf x Is Nothing

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-19
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-28
      • 2019-07-25
      相关资源
      最近更新 更多