在Rubberduck 2.0.11.2453中运行代码检查后,有4个Range引用被标记为:
成员'Range'隐式引用ActiveSheet
有问题的范围是指命名范围.是否有必要限定命名范围参考?
Private Sub RunORatio(ByVal TabNum As Integer)
Dim Start As Integer, Cat As Integer, iMth As Integer, CurrentRow As Integer, Report As Integer
Dim wsORatio As Worksheet, wsData As Worksheet, wsMacro As Worksheet
Dim sMap As String, Test As String
With ActiveWorkbook
Set wsMacro = .Worksheets("Macro")
Set wsORatio = .Worksheets("ORatio" & TabNum)
With wsORatio
sMap = "oratio" & TabNum & "map"
For CurrentRow = 1 To Range(sMap).Rows.Count '<---1 here
Test = Range(sMap).Cells(CurrentRow, 1) '<---1 Here
Set wsData = ActiveWorkbook.Worksheets(Test)
Start = Range(Range(sMap).Cells(CurrentRow, 2)).Row '<---2 Here
Report = wsMacro.Range(sMap).Cells(CurrentRow, 3)
For Cat = 0 To 12
For iMth = 1 To 12
wsORatio.Cells(Report + Cat, 7 + iMth) = wsData.Cells(Start + Cat, 37 + iMth)
Next iMth
Next Cat
Next CurrentRow
End With
End With
End Sub
Run Code Online (Sandbox Code Playgroud)
Mat*_*don 10
免责声明:我积极参与Rubberduck的开发.
考虑这个常见的错误:
lastRow = Worksheets("Sheet12").Cells(1, Rows.Count).End(xlUp).Row
Run Code Online (Sandbox Code Playgroud)
Rows是不合格的,因此隐含地指活动表,因此Rows.Count不一定是"Sheet12"上的行计数.代码可能会起作用,但它也可能导致一个细微的错误,lastRow因为这个错误,因此具有正确的值,具体取决于活动工作表的内容.
或者这一个:
ActiveWorkbook.Worksheets("SummarySheet") _
.ListObjects("Table1").Sort.SortFields.Add _
Key:=Range("Table1[[#All],["Date]]"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortTextAsNumbers
Run Code Online (Sandbox Code Playgroud)
看见?因为Key参数不合格,所以调用将在运行时失败,错误1004 - 对象'_Global'的"方法'范围'失败".这是169 Stack Overflow问题."错误1004"产生1465 Stack Overflow问题.
对活动工作表的隐式引用是错误的常见原因.
Rubberduck的VBA代码检查与ReSharper的C#静态代码分析一样,提示/建议.该工具告诉您,这里可能存在可能导致问题的内容,或者使代码不那么明确.
你需要完全符合每一个Range电话的资格吗?当然不是 - Rubberduck只是让你知道,在这些情况下,ActiveSheet隐含地被引用,这就是它的全部内容.
你总是可以使用"忽略一次"快速修复来告诉Rubberduck"看,我知道我在做什么":

该"修复"插入一个特殊注释(内部,Rubberduck称之为"注释"),指示检查忽略特定结果,同时启用检查:
With ActiveWorkbook
Set wsMacro = .Worksheets("Macro")
Set wsORatio = .Worksheets("ORatio" & TabNum)
With wsORatio
sMap = "oratio" & TabNum & "map"
'@Ignore ImplicitActiveSheetReference
For CurrentRow = 1 To Range(sMap).Rows.Count
'@Ignore ImplicitActiveSheetReference
Test = Range(sMap).Cells(CurrentRow, 1)
Set wsData = ActiveWorkbook.Worksheets(Test)
'@Ignore ImplicitActiveSheetReference
Start = Range(Range(sMap).Cells(CurrentRow, 2)).Row
Report = wsMacro.Range(sMap).Cells(CurrentRow, 3)
For Cat = 0 To 12
For iMth = 1 To 12
wsORatio.Cells(Report + Cat, 7 + iMth) = wsData.Cells(Start + Cat, 37 + iMth)
Next iMth
Next Cat
Next CurrentRow
End With
End With
Run Code Online (Sandbox Code Playgroud)
这些注释的优点是告诉读者(未来你或者任何接受你的代码的人),这里有一些东西.
未来版本最终将支持@Ignore在模块级别指定注释,以忽略整个模块中特定检查的所有结果.
请注意,检查属于可维护性和可读性问题类别.Range("DefinedName")不像以下那样明确和失败安全的一半:
ActiveWorkbook.Names("DefinedName").RefersToRange
Run Code Online (Sandbox Code Playgroud)
这给了你相同的范围,并且读取它实际上是在工作簿级别提取范围的命名范围.
免责声明:我也参与了Rubberduck的开发.
正如@Mat'sMug已经指出的那样,检查会为您提供有关代码的信息.你对这些信息的处理方式是偏好,编码信号等.
在这种情况下,检查不会告诉您代码中存在错误,它告诉您隐式对象引用可能会导致代码以意外方式运行. 从这次特定检查中得出的结论是,您要让Excel决定如何解释您所指的对象.
从该文件为Application.Range:
在没有对象限定符的情况下使用时,此属性是ActiveSheet.Range的快捷方式(它从活动工作表中返回一个范围;如果活动工作表不是工作表,则属性将失败).
最后一句话是你不应该忽略这个检查的第一个原因 - Range如果你有一个Chart选择,没有限定符会抛出.这就是为什么你应该使用Workbook.Worksheets(foo)而不是Workbook.Sheets(foo)你分配给一个Worksheet(这实际上是在Rubberduck检查愿望清单上)的原因.
第二个原因与第一个原因有关.正如您在评论中正确指出的那样,"命名范围有一个工作表名称作为其引用的一部分",或者改写为"命名范围可以假定为唯一".但是,如果您打开多个工作簿,则不必是唯一的.由于ActiveSheet是始终从返回ActiveWorkbook在调用的时候,如果Workbook代码预期不活跃,该代码或者抛出或返回不正确Range(如果其他Workbook不约而同地包含Range具有相同的名称).
请记住,尽管该With块会捕获一个硬引用ActiveWorkbook,Application但不会 - 并且ActiveWorkbook可能会在代码执行过程中发生变化.这一切都与您应该避免使用ActiveFoo对象的原因有关- 它们引入了错误将由其他"正确"代码导致的可能性.
解决方案很简单.只需在它们前面添加点.这样他们就会Workbook.Range通过With块中的捕获硬引用来调用而不是Application.Range.