如何修复运行时错误1004方法对象全局范围失败

时间:2019-08-14 20:55:51

标签: excel vba

嗨,我正在尝试运行此代码,并且该代码以前在其他项目上也可以使用,所以我不明白为什么它不能在此代码上使用。

我试图查看我是否错过了先前代码中的内容,但我不认为自己

    Sub DepolPotential()
    DataSheet.Activate
    Dim DepolPotential As Range
    Dim Count1 As Range
    Dim Cells1 As Range
    Dim Count2 As Range
    Set Cells1 = Range("N2", Range("N2").End(xlDown))
    Set Cells2 = Range("N2", Range("N2").End(xlDown))
    Set Count2 = Range("N2")

    Do
    Set Cells1 = Range(Count2, Range("N2").End(xlDown))
    Set Count1 = Count2
    For Each Count1 In Cells1
      If Count2 Is Nothing Then
        Exit Do
      End If
      If Count1.Value < 1 And Count1.Offset(3, 0).Value < 1 Then
        Set DepolPotential = Count1.Offset(0, -12)
         Count1.Offset(0, 20).Value = DepolPotential.Value
         Exit For
      End If
    Next Count1
    Dim InstOn As Range
      If Count1 Is Nothing Then
        Exit Do
      End If
   Set Cells2 = Range(Count1, Range("N2").End(xlDown))
   For Each Count2 In Cells2
    If Count2.Value > 1 And Count1.Offset(3, 0).Value > 1 Then
      Set InstOn = Count2.Offset(0, -12)
      Count2.Offset(0, 21).Value = InstOn.Value
      Count2.Offset(1, 22).Value = InstOn.Offset(1, 0).Value
      Set Count2 = Count2.Offset(2, 0)
      Exit For
    End If
   Next Count2
   Loop Until Count1 Is Nothing

我在网上遇到错误

Set Cells1 = Range(Count2, Range("N2").End(xlDown)) 

我不确定为什么以前的代码中出现此错误,但并没有给我一个错误。

2 个答案:

答案 0 :(得分:4)

我不知道您的数据是什么样子,但是外循环在第二次迭代时以空DataSheet中断,并出现您描述的错误。这是一件好事,因为cells1.Address在空白表上是$N$2:$N$1048576……但这没关系,因为第一个空单元格满足条件并退出了第一个内部循环。

但这只是一种症状,而不是真正的问题。

第二个循环将迭代与第一个循环完全相同的范围,但是这次没有一个空单元格满足条件,并且该循环继续迭代工作表上的每个痛苦行。

当该循环退出时,count2循环变量引用为Nothing-这就是第二次迭代爆炸的原因:[_Global|Worksheet].Range接受几种不同的方法来指定单元格范围,但是{ {1}}是非法的说法。它会引发错误,并突然停止执行。

发生了什么事? VBA语言规范与此处相关:

  

Nothing执行完毕后,<for-each-statement>的值就是<bound-variable-expression>中最后一个元素的数据值。

     

https://docs.microsoft.com/en-us/openspecs/microsoft_general_purpose_programming_languages/ms-vbal/b132463a-fd25-4143-8fc7-a443930e0651

按照规范,<collection>count1都应该在退出循环时具有有效的对象引用。但是,似乎Microsoft对VBA语言规范的实现工作有所不同。这是一个最小的repro示例:

count2

运行该代码一次,将Public Sub Test() Dim c As Collection Set c = New Collection c.Add New Collection 'any object will do Dim o As Object For Each o In c 'Exit For Next Debug.Print o Is Nothing End Sub 注释掉,然后取消注释该语句并再次运行它。如果循环运行到完成,则Exit For循环的For Each循环的“绑定变量”将为Nothing

这意味着,如果第一个内部循环执行完毕,那么您在这里将遇到相同的错误:

  Set Cells2 = Range(Count1, Range("N2").End(xlDown))

因为那时Count1将是Nothing。在空白表上,Count1指向$N$2,因此Cells2变为$N$2:$N$1048576

当第二个内部循环运行完成时,Count2Nothing,并且由于循环条件仅查看Count1 ...

 Loop Until Count1 Is Nothing

...当将Count2作为参数传递给_Global.Range时,外循环的第二次迭代失败,该错误失败,错误1004:

  Set Cells1 = Range(Count2, Range("N2").End(xlDown))

我认为创可贴可以解决verify whether Count2 Is Nothing before using it,尽管这与更改退出条件以同时检查Count1Count2相同:

Loop Until Count1 Is Nothing Or Count2 Is Nothing

...而且我认为这不是正确的解决方案。实际上,我不确定这是 a 解决方案。

我不能百分百确定,因为我没有花太多时间试图弄清楚Count2不是Nothing对外部循环的影响(加上我没有任何数据玩),但我认为这可能恰好在做同一件事:

Dim interestingCells As Range
Set interestingCells = DataSheet.Range("N2:N" & DataSheet.Rows.Count).End(xlUp)

Dim cell As Range
For Each cell In interestingCells
    If cell.Value < 1 And cell.Offset(3).Value < 1 Then
        cell.Offset(0, 20).Value = cell.Offset(0, -12).Value
    ElseIf cell.Value > 1 And cell.Offset(3).Value > 1 Then
        cell.Offset(0, 21).Value = cell.Offset(0, -12).Value
        cell.Offset(1, 22).Value = cell.Offset(1).Value
    End If
Next

老实说,我认为 real 解决方案是退后一步,然后准确地重新评估该循环的含义,废弃旧代码并从头开始重写它。其他任何事情都会增加本来就难以理解的代码的复杂性。除了回收的For Each循环变量之外, row 偏移量尤其令人困惑:详细说明为什么下一行需要受影响的注释将按顺序排列-注意这样的逻辑可能要求以特定的方式对数据进行排序...这可能是一个错误的假设,例如,一个灾难性的错误等待显示其丑陋的头。另请注意,如果迭代范围恰好覆盖整个列,则cell.Offset(n)在最后一行时,n的任何正值cell都会失败,并且如果{<1>}位于工作表的最后一行 near 附近,则大于它下面剩余的行数。

还请注意,n逻辑用于获取带有数据的最后一行/单元格:这样,一个空工作表将不会运行一次迭代。

最后,请注意明确限定的.End(xlUp)调用,以便它解析为Range而不是DataSheet.Range-这是我见过的几次错误1004之一_Global.Range的根本原因不是使用不合格的_Global.Range调用,隐式地指的是Range是什么。

答案 1 :(得分:0)

启动您的代码。 在线

Set Cells1 = Range (Count2, Range ('N2'). End (xlDown))

Count2一无所有

作为解决方案,请移动代码

If Count2 Is Nothing Then
  Exit do
End if

在行之前

Set Cells1 = Range (Count2, Range ('N2'). End (xlDown))