Access
 sql >> Datenbank >  >> RDS >> Access

VBA-Funktion zum Ändern von Groß- und Kleinschreibung

Als starker Befürworter der Versionskontrolle in Microsoft Access muss ich über meinen größten Kritikpunkt an der VBA-Entwicklungsumgebung sprechen:automatisches „Recasing“ von Bezeichnern. Betrachten Sie dies als eine Erweiterung meiner Antwort auf eine Frage zu diesem "Feature" bei stackoverflow.

Ich werde diesen Artikel in zwei Teilen angehen. In Teil 1 werde ich das Verhalten der Entwicklungsumgebung definieren. In Teil 2 werde ich meine Theorie diskutieren, warum es so funktioniert.

Teil 1:Definieren des Verhaltens

Wenn Sie viel Zeit mit dem Schreiben von Code in VBA verbracht haben, bin ich sicher, dass Ihnen dieses „Feature“ aufgefallen ist. Während Sie Bezeichner – Variablen, Funktionsnamen, Aufzählungen usw. – eingeben, stellen Sie möglicherweise fest, dass die IDE automatisch die Groß- und Kleinschreibung dieser Bezeichner ändert. Sie können beispielsweise einen Variablennamen nur in Kleinbuchstaben eingeben, aber sobald Sie in eine neue Zeile wechseln, wird der erste Buchstabe Ihrer Variablen  plötzlich in Großbuchstaben geändert.

Das erste Mal, wenn Sie dies sehen, kann es erschütternd sein. Während Sie mit dem Programmieren fortfahren, ändert die IDE die Groß- und Kleinschreibung scheinbar willkürlich. Aber wenn Sie genug Zeit in der IDE verbringen, offenbart sich das Muster schließlich von selbst.

Damit Sie nicht mehr als zehn Jahre Ihres Lebens darauf warten müssen, dass sich das Muster Ihnen offenbart, werde ich das Muster jetzt so beschreiben, wie ich es verstanden habe. Meines Wissens hat  Microsoft dieses Verhalten nie offiziell dokumentiert.

  1. Alle automatischen Falländerungen gelten global für das VBA-Projekt.
  2. Immer wenn die Deklarationszeile einer der folgenden Arten von Bezeichnern geändert wird, ändert sich auch die Groß- und Kleinschreibung aller anderen Bezeichner mit demselben Namen:
    • Untername
    • Funktionsname
    • Name eingeben
    • Aufzählungsname
    • Variablenname
    • Konstanter Name
    • Eigenschaftsname
  3. Immer wenn der Name eines Enum-Elements irgendwo im Code geändert wird, wird die Groß- und Kleinschreibung des Enum-Elementnamens aktualisiert, damit sie überall übereinstimmt.

Lassen Sie uns jetzt etwas detaillierter über jedes dieser Verhaltensweisen sprechen.

Globale Änderungen

Wie ich oben geschrieben habe, sind Identifier-Case-Änderungen global für ein VBA-Projekt. Mit anderen Worten, die VBA-IDE ignoriert den Geltungsbereich vollständig, wenn die Groß-/Kleinschreibung von Bezeichnern geändert wird.

Angenommen, Sie haben eine private Funktion mit dem Namen AccountIsActive in einem Standardmodul. Stellen Sie sich nun ein Klassenmodul an einer anderen Stelle in demselben Projekt vor. Das Klassenmodul hat eine private Property Get-Prozedur. Innerhalb dieser Property Get-Prozedur befindet sich eine lokale Variable namens accountIsActive . Sobald Sie die Zeile Dim accountIsActive As Boolean eingeben in die VBA-IDE und wechseln Sie in eine neue Zeile, die Funktion KontoIstAktiv die wir separat in einem eigenen Standardmodul definiert haben, hat seine Deklarationszeile in Private Function accountIsActive() geändert um die lokale Variable innerhalb dieses Klassenmoduls abzugleichen.

Das ist ein Bissen, also lass es mich besser im Code demonstrieren.

Schritt 1:AccountIsActive-Funktion definieren

'--== Module1 ==--
Private Function AccountIsActive() As Boolean
End Function

Schritt 2:Deklarieren Sie die lokale Variable accountIsActive in einem anderen Bereich

'--== Class1 ==--
Private Sub Foo()
    Dim accountIsACTIVE As Boolean
End Sub

Schritt 3:VBA-IDE ... was haben Sie getan?!?!

'--== Module1 ==--
Private Function accountIsACTIVE() As Boolean
End Function

Nichtdiskriminierungsrichtlinie von VBA Case-Obliteration

VBA begnügt sich nicht damit, den Geltungsbereich einfach zu ignorieren, sondern ignoriert auch die Unterschiede zwischen den Arten von Bezeichnern, um eine konsistente Groß- und Kleinschreibung zu erreichen. Mit anderen Worten, jedes Mal, wenn Sie eine neue Funktion, Unterroutine oder Variable deklarieren, die einen vorhandenen Bezeichnernamen verwendet, wird die Groß-/Kleinschreibung aller anderen Instanzen dieses Bezeichners entsprechend geändert.

In jedem dieser Beispiele unten ändere ich nur das erste aufgeführte Modul. Die VBA-IDE ist für alle anderen Änderungen an zuvor definierten Modulen verantwortlich.

Schritt 1:Funktion definieren

'--== Module1 ==--
Public Function ReloadDBData() As Boolean
End Function

Schritt 2:Sub mit demselben Namen definieren

HINWEIS:Dies gilt vollkommen, solange sich die Prozeduren in verschiedenen Modulen befinden. Das heißt, nur weil Sie etwas tun *können*, heißt das nicht, dass Sie *sollten*. Und Sie *sollten* diese Situation möglichst vermeiden.

'--== Module2 ==--
Public Sub ReloadDbData()
End Sub

'--== Module1 ==--
Public Function ReloadDbData() As Boolean
End Sub

Schritt 3:Definieren Sie einen Typ mit demselben Namen

HINWEIS:Nochmals, bitte definieren Sie keine Subs, Funktionen und Typen mit demselben Namen in einem einzigen Projekt.

'--== Module3 ==--
Private Type ReLoadDBData
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub ReLoadDBData()
End Sub

'--== Module1 ==--
Public Function ReLoadDBData() As Boolean
End Sub

Schritt 4:Definieren Sie eine Aufzählung mit demselben Namen

HINWEIS:Bitte, bitte, bitte, aus Liebe zu allen heiligen Dingen ...

'--== Module4 ==--
Public Enum ReloadDbDATA
    Dummy
End Enum

'--== Module3 ==--
Private Type ReloadDbDATA
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub ReloadDbDATA()
End Sub

'--== Module1 ==--
Public Function ReloadDbDATA() As Boolean
End Sub

Schritt 5:Definieren Sie eine Variable mit demselben Namen

HINWEIS:Machen wir das eigentlich immer noch?

'--== Module5 ==--
Public reloaddbdata As Boolean

'--== Module4 ==--
Public Enum reloaddbdata
    Dummy
End Enum

'--== Module3 ==--
Private Type reloaddbdata
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub reloaddbdata()
End Sub

'--== Module1 ==--
Public Function reloaddbdata() As Boolean
End Sub

Schritt 6:Definieren Sie eine Konstante mit demselben Namen

HINWEIS:Oh, komm schon. Im Ernst?

'--== Module6 ==--
Private Const RELOADDBDATA As Boolean = True

'--== Module5 ==--
Public RELOADDBDATA As Boolean

'--== Module4 ==--
Public Enum RELOADDBDATA
    Dummy
End Enum

'--== Module3 ==--
Private Type RELOADDBDATA
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub RELOADDBDATA()
End Sub

'--== Module1 ==--
Public Function RELOADDBDATA() As Boolean
End Sub

Schritt 7:Definieren Sie eine Klasseneigenschaft mit demselben Namen

HINWEIS:Das wird langsam albern.

'--== Class1 ==--
Private Property Get reloadDBData() As Boolean
End Property

'--== Module6 ==--
Private Const reloadDBData As Boolean = True

'--== Module5 ==--
Public reloadDBData As Boolean

'--== Module4 ==--
Public Enum reloadDBData
    Dummy
End Enum

'--== Module3 ==--
Private Type reloadDBData
    Dummy As Variant
End Type

'--== Module2 ==--
Public Sub reloadDBData()
End Sub

'--== Module1 ==--
Public Function reloadDBData() As Boolean
End Sub

Enum-Elemente?!?!

Für diesen dritten Punkt ist es wichtig, zwischen einem Enum-Typ zu unterscheiden und ein Enum-Element .

Enum EnumTypeName   ' <-- Enum type
    EnumItemAlice   ' <-- Enum item
    EnumItemBob     ' <-- Enum item
End Enum

Wir haben oben bereits gezeigt, dass Enum-Typen genauso behandelt werden wie andere Arten von Deklarationen, wie Subs, Funktionen, Konstanten und Variablen. Immer wenn die Deklarationszeile für einen Bezeichner mit diesem Namen geändert wird, wird die Schreibweise jedes anderen Bezeichners im Projekt mit demselben Namen aktualisiert, um der letzten Änderung zu entsprechen.

Elemente aufzählen sind insofern etwas Besonderes, als sie die einzige Art von Bezeichnern sind, deren Groß- und Kleinschreibung geändert werden kann, wenn jede Codezeile verwendet wird das den Aufzählungselementnamen enthält, wird geändert.

Schritt 1. Definieren und füllen Sie das Enum

'--== Module7 ==--
Public Enum EnumTypeName
    EnumItemAlice
    EnumItemBob
End Enum

Schritt 2. Auf die Enum-Elemente im Code verweisen

'--== Module8 ==--
Sub TestEnum()
    Debug.Print EnumItemALICE, EnumItemBOB
End Sub

Ergebnis:Enum-Typ-Deklaration ändert sich, um mit regulärer Codezeile übereinzustimmen

'--== Module7 ==--
Public Enum EnumTypeName
    EnumItemALICE
    EnumItemBOB
End Enum

Teil 2:Wie sind wir hierher gekommen?

Ich habe noch nie mit jemandem aus dem internen VBA-Entwicklungsteam gesprochen. Ich habe noch nie eine offizielle Dokumentation darüber gesehen, warum die VBA-IDE so funktioniert, wie sie es tut. Also, was ich gleich schreiben werde, ist reine Vermutung, aber ich denke, es macht Sinn.

Lange habe ich mich gefragt, warum um alles in der Welt die VBA-IDE dieses Verhalten zeigt. Schließlich ist es eindeutig beabsichtigt. Das Einfachste für die IDE wäre ... nichts. Wenn der Benutzer eine Variable in Großbuchstaben deklariert, lassen Sie sie in Großbuchstaben stehen. Wenn der Benutzer dann einige Zeilen später in Kleinbuchstaben auf diese Variable verweist, belassen Sie diese Referenz in Kleinbuchstaben und die ursprüngliche Deklaration in Großbuchstaben.

Dies wäre eine vollkommen akzeptable Implementierung der VBA-Sprache. Schließlich ist die Sprache selbst case-insensitive. Warum sich also all die Mühe machen, die Groß- und Kleinschreibung der Kennung automatisch zu ändern?

Ironischerweise glaube ich, dass die Motivation darin bestand, Verwirrung zu vermeiden. (Swing and a miss, wenn Sie mich fragen.)  Ich spotte über diese Erklärung, aber sie ergibt einen Sinn.

Kontrast mit Sprachen, bei denen die Groß-/Kleinschreibung beachtet wird

Lassen Sie uns zuerst über Programmierer sprechen, die aus einer Sprache kommen, die zwischen Groß- und Kleinschreibung unterscheidet. Eine übliche Konvention in Sprachen, bei denen die Groß-/Kleinschreibung beachtet wird, wie z. B. C#, besteht darin, Klassenobjekte mit Großbuchstaben zu benennen und Instanzen dieser Objekte denselben Namen wie die Klasse zu geben, jedoch mit einem führenden Kleinbuchstaben.

Diese Konvention funktioniert in VBA nicht, da zwei Bezeichner, die sich nur in der Groß-/Kleinschreibung unterscheiden, als gleichwertig angesehen werden. Tatsächlich lässt die Office-VBA-IDE nicht zu, dass Sie gleichzeitig eine Funktion mit einer Art von Groß- und Kleinschreibung und eine lokale Variable mit einer anderen Art von Groß-/Kleinschreibung deklarieren (wir haben dies ausführlich oben behandelt). Dies verhindert, dass der Entwickler davon ausgeht, dass es einen semantischen Unterschied zwischen zwei Bezeichnern mit denselben Buchstaben, aber unterschiedlicher Schreibweise gibt.

Falschen Code falsch aussehen lassen

Die wahrscheinlichere Erklärung meiner Meinung nach ist, dass diese "Funktion" existiert, um äquivalente Bezeichner identisch aussehen zu lassen. Denk darüber nach; Ohne diese Funktion könnten Tippfehler leicht zu Laufzeitfehlern werden. Glauben Sie mir nicht? Bedenken Sie Folgendes:

Private mAccountName As String
Private Const ACCOUNT_NAME As String = "New User"

Private Sub Class_Initialize()
    mAccountName = ACCOUNT_NAME
End Sub

Public Property Get MyAccountName() As String
    MAccountName = Account_Name
End Property

Public Property Let MyAccountName(AccountName As String)
    mAccountName = Account_Name
End Property

Wenn Sie sich den obigen Code schnell ansehen, sieht er ziemlich einfach aus. Es ist eine Klasse mit einem .MyAccountName Eigentum. Die Mitgliedsvariable für die Eigenschaft wird beim Erstellen des Objekts mit einem konstanten Wert initialisiert. Beim Festlegen des Kontonamens im Code wird die Mitgliedsvariable erneut aktualisiert. Beim Abrufen des Eigenschaftswerts gibt der Code lediglich den Inhalt der Mitgliedsvariablen zurück.

Zumindest soll es das tun. Wenn ich den obigen Code kopiere und in ein VBA-IDE-Fenster einfüge, wird die Groß- und Kleinschreibung der Bezeichner konsistent und die Laufzeitfehler zeigen sich plötzlich:

Private mAccountName As String
Private Const ACCOUNT_NAME As String = "New User"

Private Sub Class_Initialize()
    mAccountName = ACCOUNT_NAME   ' <- This is OK
End Sub

Public Property Get MyAccountName() As String
    mAccountName = ACCOUNT_NAME   ' <- This is probably not what we intended
End Property

Public Property Let MyAccountName(AccountName As String)
    mAccountName = ACCOUNT_NAME   ' <- This is definitely not what we meant
End Property

Umsetzung:Ist das wirklich der beste Ansatz?

Ähm nein. Versteh mich nicht falsch. Ich mag die Idee, die Großschreibung von Bezeichnern automatisch zu ändern, um die Konsistenz zu wahren. Mein einziger wirklicher Kritikpunkt ist, dass die Änderung an jeder Kennung mit diesem Namen im gesamten Projekt vorgenommen wird. Viel besser wäre es, die Großschreibung nur der Bezeichner zu ändern, die sich auf dasselbe "Ding" beziehen (ob dieses "Ding" eine Funktion, ein Unterobjekt, eine Eigenschaft, eine Variable usw. ist).

Warum funktioniert es also nicht so? Ich gehe davon aus, dass die VBA-IDE-Entwickler meiner Sichtweise zustimmen, wie es funktionieren sollte. Aber es gibt einen sehr guten Grund warum die IDE nicht so funktioniert. Mit einem Wort, Leistung.

Leider gibt es nur einen zuverlässigen Weg, um herauszufinden, welche Bezeichner mit demselben Namen tatsächlich auf dasselbe verweisen:Analysieren Sie jede Codezeile. Das ist langsam. Das ist mehr als eine einfache Hypothese meinerseits. Das VBA-Projekt Rubberduck macht genau das; Es analysiert jede Codezeile im Projekt, sodass es eine automatisierte Codeanalyse und eine Menge anderer cooler Sachen durchführen kann.

Das Projekt ist zugegebenermaßen ein Schwergewicht. Es funktioniert wahrscheinlich hervorragend für Excel-Projekte. Leider war ich nie geduldig genug, um es in einem meiner Access-Projekte zu verwenden. Rubberduck VBA ist ein technisch beeindruckendes Projekt, aber es ist auch eine warnende Geschichte. Es wäre schön, den Gültigkeitsbereich beim Ändern der Groß- und Kleinschreibung für Bezeichner zu berücksichtigen, aber nicht auf Kosten der derzeit blitzschnellen Leistung der VBA-IDE.

Abschließende Gedanken

Ich verstehe die Motivation für diese Funktion. Ich glaube, ich verstehe sogar, warum es so implementiert ist, wie es ist. Aber es ist für mich die verrückteste Eigenart von VBA.

Wenn ich dem Office VBA-Entwicklungsteam eine einzige Empfehlung aussprechen könnte, wäre es, eine Einstellung in der IDE anzubieten, um automatische Groß- und Kleinschreibung zu deaktivieren. Das aktuelle Verhalten könnte standardmäßig aktiviert bleiben. Aber für erfahrene Benutzer, die versuchen, sich in Versionskontrollsysteme zu integrieren, könnte das Verhalten vollständig deaktiviert werden, um zu verhindern, dass lästige „Codeänderungen“ den Revisionsverlauf verschmutzen.