2017-02-01 3 views
6

Nach den Code-Inspektionen in Rubber läuft 2.0.11.2453 gibt es 4 Bereich Referenzen, die getaggt erhalten als:Code-Inspektion - benannten Bereich Referenz

Mitglied 'Range' implizit verweist Active

Die Bereiche beziehen sich auf Named Ranges. Ist es erforderlich, eine benannte Bereichsreferenz zu qualifizieren?

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 
+0

Da Sie nicht Ihren gesamten Code (wahrscheinlich zu lang) geteilt haben, ist 'sMap' als' Name' definiert? hast du es auf eine 'Range' gesetzt? –

+0

Ich habe, das einzige, was ausgelassen sind die Deklarationen ... hinzugefügt – Rdster

+0

Was ist der Umfang Ihrer benannten Bereiche "oratio1map" ...? Ist es Arbeitsbuch? Sie sollten das Blatt angeben, in dem der Bereich definiert ist, um dieses Tag zu vermeiden, zB 'Sheets (" SheetName "). Bereich (...)'! – R3uK

Antwort

9

Disclaimer: Ich in der Entwicklung von Rubber stark involviert bin.

diese häufigen Fehler vor:

lastRow = Worksheets("Sheet12").Cells(1, Rows.Count).End(xlUp).Row 

Rows unqualifiziert ist, und deshalb bezieht sich implizit auf das aktive Blatt und deshalb ist Rows.Count nicht unbedingt die Zeilenanzahl auf „Sheet12“. Der Code könnte funktionieren, aber es könnte auch zu einem subtilen Fehler führen, bei dem lastRow nicht den richtigen Wert hat, abhängig vom Inhalt des aktiven Blattes.

Oder diese:

ActiveWorkbook.Worksheets("SummarySheet") _ 
    .ListObjects("Table1").Sort.SortFields.Add _ 
     Key:=Range("Table1[[#All],["Date]]"), _  
     SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortTextAsNumbers 

es sehen? Da der Parameter Key nicht qualifiziert ist, wird der Aufruf zur Laufzeit mit Fehler 1004 - "Methode 'Range' des Objekts '_Global' failed" fehlschlagen. Das ist 169 Stack Overflow questions. "Fehler 1004" ergibt 1465 Stack Overflow questions.

Implizite Verweise auf das aktive Arbeitsblatt sind eine häufige Ursache für Fehler.


Rubber der VBA Code-Inspektionen sind, wie ReSharper der C# statische Code-Analyse, Hinweise/Anregungen. Das Tool sagt Ihnen, dass es hier etwas gibt, das könnte verursachen Probleme, oder das macht den Code weniger explizit als es sein könnte.

Sie tun Notwendigkeit voll jeden einzelnen Range Anruf zu qualifizieren? Natürlich nicht - Rubberduck lässt Sie nur wissen, dass in diesen Fällen ActiveSheet implizit referenziert wird, das ist alles, was dazu gehört.

Sie können immer sagen, Rubberduck „aussehen, ich weiß, was ich tue“, mit dem „einmal ignorieren“ quick-fix:

ignore once

Das „fix“ fügt einen speziellen Kommentar (intern , Rubber sie „Anmerkungen“) aufruft, die die Inspektion weist bestimmte Ergebnisse zu ignorieren, während die Inspektion verlassen aktiviert:

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 

Diese Anmerkungen haben den Vorteil, sagen die Leser (Zukunft Sie, oder wer auch immer nimmt der Code über) Das hier ist etwas los.

Zukünftige Versionen unterstützen eventuell die Angabe von @Ignore Annotationen einmal auf Modulebene, um alle Ergebnisse einer bestimmten Inspektion in einem ganzen Modul zu ignorieren.


Beachten Sie, dass die Inspektion unter der Wartbarkeit und Ablesbarkeit Probleme Kategorie. Range("DefinedName") ist nicht halb so explizit und ausfallsicher wie:

ActiveWorkbook.Names("DefinedName").RefersToRange 

dem Sie den gleichen Bereich gibt, und liest sich wie es tatsächlich ist ein benannter Bereich scoped auf Arbeitsmappe Ebene ziehen.

+2

Ok, das kann ich verstehen. Ich habe ziemlich viel darüber gelernt, welche Warnungen mein Code auslöst. Dies ist jedoch, dass der benannte Bereich hat das Arbeitsblatt als ActiveWorkbook.Names ("Oratio1map") = "= Makro! $ I $ 14: $ L $ 16" ... scheint fast überflüssig, ActiveWorkbook.Sheets ("Macro" verwenden)) .Range ("oratio1map"), wenn sich der Blattname bereits im Bereich befindet. Wenn das jedoch hilft, Fehler oder Bugs zu eliminieren, dann nehme ich an, dass ich damit anfangen werde und den Rng benutze, wie Shai es auch vorgeschlagen hat. – Rdster

7

Haftungsausschluss: Ich bin auch an der Entwicklung von Rubberduck beteiligt.

Wie @ Mat'sMug bereits darauf hingewiesen hat, liefert Ihnen die Inspektion Informationen über den Code. Was Sie tun mit dieser Information ist eine Frage der Präferenz, Codierung sytle, etc.

In diesem Fall sagt Ihnen die Inspektion nicht, dass es einen Fehler in Ihrem Code ist, es sagt Ihnen, dass es ein Potenzial, dass implizite Objektreferenzen dazu führen, dass sich Ihr Code auf unerwartete Weise verhält. Der Takeaway von dieser spezifischen Inspektion ist, dass Sie Excel entscheiden lassen, wie interpretiert wird, auf welches Objekt Sie sich beziehen.

Von the documentation für Application.Range:

Wenn ohne ein Objekt Qualifier verwendet, diese Eigenschaft ist eine Abkürzung für ActiveSheet.Range (es gibt einen Bereich von dem aktiven Blatt, wenn das aktiven Blatt isn‘ In einem Arbeitsblatt schlägt die Eigenschaft fehl.

Der letzte Satz ist der erste Grund, warum Sie nicht diese Prüfung ignorieren sollte - Range ohne Qualifier wird ausgelöst, wenn Sie eine Chart haben ausgewählt. Dies ist der gleiche Grund, warum Sie Workbook.Worksheets(foo) anstelle von Workbook.Sheets(foo) verwenden sollten, wenn Sie einem Worksheet (das ist eigentlich on the Rubberduck inspection wish-list) zuweisen.

Der zweite Grund bezieht sich auf den ersten. Wie Sie in den Kommentaren richtig angeben, "der benannte Bereich hat einen Blattnamen als Teil seiner Referenz", oder umformuliert "ein benannter Bereich kann als einzigartig angenommen werden". Aber es nicht muss eindeutig sein, wenn Sie mehr als eine Arbeitsmappe geöffnet haben. Da ActiveSheet ist immer vom ActiveWorkbook zum Zeitpunkt des Aufrufs zurückgegeben, wenn die Workbook der Code erwartet nicht aktiv ist, wird entweder dieser Code werfen oder die falschen Range zurückzukehren (wenn die anderen Workbook zufällig ein Range mit der enthält gleicher Name).

Beachten Sie, dass, obwohl der With Block einen harten Verweis auf ActiveWorkbook einfängt, Application nicht - und ActiveWorkbook kann im Laufe Ihres Codes Ausführung ändern.Dies alles hängt mit den Gründen zusammen, warum Sie die Verwendung der ActiveFoo Objekte vermeiden sollten - sie führen die Möglichkeit ein, dass Fehler von sonst "korrektem" Code resultieren.

Die Lösung ist einfach. Fügen Sie einfach den Punkt vor ihnen hinzu. Auf diese Weise rufen sie Workbook.Range über die erfasste harte Referenz aus dem With Block statt Application.Range.

+3

Das macht Sinn, und wenn man bedenkt, dass der Typ, der hier vor mir war, in jedes Arbeitsbuch ein "Makro" -Blatt legte ... das Arbeitsbuch jetzt eindeutig als eine wirklich gute Idee bezeichnet. Ich nehme an, dass ich angenommen habe, dass ein benannter Bereich diese Arbeitsmappe irgendwie zusammen mit dem Blattnamen enthalten würde. – Rdster

+2

@Rdster - Einfache Kontrolle zu machen. Sie können dies sehen, indem Sie einen Bereich mit dem Namen "Foo" in 2 Arbeitsmappen definieren und anschließend 'Debug.Print Range (" Foo "). Value" mit jedem von ihnen ausführen. – Comintern

Verwandte Themen