sql >> Databáze >  >> RDS >> Access

Funkce změny velikosti písmen VBA

Jako silný zastánce správy verzí v Microsoft Access musím mluvit o svém největším trápení s vývojovým prostředím VBA:o automatickém „přebalování“ identifikátorů. Berte to jako rozšíření mé odpovědi na otázku týkající se této "funkce" na stackoverflow.

K tomuto článku přistoupím ve dvou částech. V 1. části budu definovat chování vývojového prostředí. V části 2 proberu svou teorii o tom, proč to takto funguje.

Část 1:Definice chování

Pokud jste strávili nějaké množství času psaním kódu ve VBA, jsem si jistý, že jste si této „funkce“ všimli. Při psaní identifikátorů – proměnných, názvů funkcí, výčtů atd. – si můžete všimnout, že IDE automaticky mění velká a malá písmena těchto identifikátorů. Můžete například napsat název proměnné všemi malými písmeny, ale jakmile se přesunete na nový řádek, první písmeno vaší proměnné se náhle přepne na velké.

Když to vidíte poprvé, může to být nepříjemné. Jak pokračujete v programování, IDE stále mění případ na vás zdánlivě náhodně. Ale pokud strávíte dostatek času v IDE, vzor se nakonec sám odhalí.

Abych vás uchránil před tím, že budete muset strávit více než deset let svého života čekáním, až se vám vzorec odhalí, popíšu nyní vzorec tak, jak jsem mu porozuměl. Pokud je mi známo,  Microsoft nikdy oficiálně nezdokumentoval žádné z tohoto chování.

  1. Všechny automatické změny velkých a malých písmen jsou pro projekt VBA globální.
  2. Kdykoli se změní řádek deklarace některého z následujících typů identifikátorů, změní se také velká a malá písmena každého dalšího identifikátoru se stejným názvem:
    • Podjméno
    • Název funkce
    • Zadejte název
    • Název výčtu
    • Název proměnné
    • Konstantní název
    • Název nemovitosti
  3. Kdykoli se změní název položky výčtu kdekoli v kódu, velikost písmen názvu položky výčtu se aktualizuje tak, aby odpovídala všude.

Promluvme si nyní o každém z těchto chování trochu podrobněji.

Globální změny

Jak jsem psal výše, změny případu identifikátoru jsou pro projekt VBA globální. Jinými slovy, IDE VBA zcela ignoruje rozsah při změně velikosti písmen v identifikátorech.

Řekněme například, že máte soukromou funkci s názvem AccountIsActive ve standardním modulu. Nyní si představte modul třídy jinde ve stejném projektu. Modul třídy má soukromou proceduru získání vlastnosti. Uvnitř této procedury Property Get je místní proměnná s názvem accountIsActive . Jakmile napíšete řádek Dim accountIsActive As Boolean do IDE VBA a přejděte na nový řádek, funkce AccountIsActive který jsme definovali samostatně v jeho vlastním standardním modulu, má svůj deklarační řádek změněn na Private Function accountIsActive() aby odpovídala místní proměnné uvnitř tohoto modulu třídy.

To je sousto, tak mi to dovolte lépe demonstrovat v kódu.

Krok 1:Definujte funkci AccountIsActive

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

Krok 2:Deklarujte místní proměnnou accountIsActive v jiném rozsahu

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

Krok 3:VBA IDE...co jste udělali?!?!

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

Zásady nediskriminace VBA Case-Obliteration

VBA se nespokojí s tím, že jednoduše ignoruje rozsah, ale také ignoruje rozdíly mezi druhy identifikátorů ve snaze zavést konzistenci velkých a malých písmen. Jinými slovy, pokaždé, když deklarujete novou funkci, podprogram nebo proměnnou, která používá existující název identifikátoru, všechny ostatní instance tohoto identifikátoru změní velikost písmen, aby odpovídaly.

V každém z těchto příkladů níže měním pouze první modul. IDE VBA je zodpovědné za všechny ostatní změny dříve definovaných modulů.

Krok 1:Definujte funkci

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

Krok 2:Definujte podskupinu se stejným názvem

POZNÁMKA:Toto je naprosto platné, pokud jsou procedury v různých modulech. To znamená, že to, že něco *můžete* udělat, neznamená, že byste *měli*. A této situaci byste se *měli* vyhnout, pokud je to jen trochu možné.

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

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

Krok 3:Definujte typ se stejným názvem

POZNÁMKA:Znovu, prosím, nedefinujte pod, funkci a nepište všechny se stejným názvem v jednom projektu.

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

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

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

Krok 4:Definujte výčet se stejným názvem

POZNÁMKA:Prosím, prosím, prosím, z lásky ke všemu svatému...

'--== 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

Krok 5:Definujte proměnnou se stejným názvem

POZNÁMKA:Ve skutečnosti to stále děláme?

'--== 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

Krok 6:Definujte konstantu se stejným názvem

POZNÁMKA:No tak. Vážně?

'--== 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

Krok 7:Definujte vlastnost třídy se stejným názvem

POZNÁMKA:Začíná to být hloupé.

'--== 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

Vyjmenovat položky?!?!

U tohoto třetího bodu je důležité rozlišovat mezi typem výčtu a položka výčtu .

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

Již jsme si ukázali výše, že s typy Enum se zachází stejně jako s jinými druhy deklarací, jako jsou subs, funkce, konstanty a proměnné. Kdykoli se změní řádek deklarace pro identifikátor s tímto názvem, každý druhý identifikátor v projektu se stejným názvem má velká a malá písmena aktualizována tak, aby odpovídala poslední změně.

Vyjmenovat položky jsou speciální v tom, že jsou jediným druhem identifikátoru, jehož velká a malá písmena se mohou změnit, kdykoli jakýkoli řádek kódu který obsahuje název položky výčtu se změní.

Krok 1. Definujte a naplňte Enum

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

Krok 2. Podívejte se na položky Enum v kódu

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

Výsledek:Deklarace typu výčtu se změní tak, aby odpovídala běžnému řádku kódu

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

Část 2:Jak jsme se sem dostali?

Nikdy jsem nemluvil s nikým z interního vývojového týmu VBA. Nikdy jsem neviděl žádnou oficiální dokumentaci o tom, proč IDE VBA funguje tak, jak funguje. Takže to, co se chystám napsat, jsou čisté domněnky, ale myslím, že to dává určitý smysl.

Dlouho jsem se divil, proč proboha IDE VBA má toto chování. Ostatně je to zjevně záměr. Nejjednodušší věc pro IDE by bylo...nic. Pokud uživatel deklaruje proměnnou velkými písmeny, nechejte ji stát velkými písmeny. Pokud uživatel o několik řádků později na tuto proměnnou odkazuje malými písmeny, ponechte tento odkaz malými písmeny a původní deklaraci velkými písmeny.

To by byla naprosto přijatelná implementace jazyka VBA. Koneckonců, jazyk sám o sobě nerozlišuje malá a velká písmena. Proč se tedy namáhat automatickou změnou velikosti písmen?

Je ironií, že věřím, že motivací bylo vyhnout se zmatkům. (Swing and miss, jestli se mě ptáte.)  Tomuto vysvětlení se vysmívám, ale dává to smysl.

Kontrast s jazyky rozlišujícími velká a malá písmena

Nejprve si promluvme o programátorech pocházejících z jazyka rozlišujícího velká a malá písmena. Běžnou konvencí v jazycích citlivých na malá a velká písmena, jako je C#, je pojmenovávat objekty třídy velkými písmeny a instance těchto objektů pojmenovávat stejným názvem jako třída, ale počátečním malým písmenem.

Tato konvence nebude fungovat ve VBA, protože dva identifikátory, které se liší pouze velikostí písmen, jsou považovány za ekvivalentní. Ve skutečnosti vám IDE Office VBA nedovolí současně deklarovat funkci s jedním typem malých a velkých písmen a lokální proměnnou s jiným typem malých a velkých písmen (to jsme vyčerpávajícím způsobem probrali výše). To zabraňuje vývojáři předpokládat, že existuje sémantický rozdíl mezi dvěma identifikátory se stejnými písmeny, ale rozdílnými velikostmi písmen.

Špatný kód vypadá špatně

Pravděpodobnější vysvětlení v mé mysli je, že tato "funkce" existuje, aby ekvivalentní identifikátory vypadaly identicky. Přemýšlejte o tom; bez této funkce by se překlepy snadno proměnily v běhové chyby. nevěříš mi? Zvažte toto:

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

Pokud se rychle podíváte na výše uvedený kód, vypadá to docela jednoduše. Je to třída s .MyAccountName vlastnictví. Členská proměnná pro vlastnost je při vytvoření objektu inicializována na konstantní hodnotu. Při nastavování názvu účtu v kódu se členská proměnná opět aktualizuje. Při načítání hodnoty vlastnosti kód pouze vrací obsah členské proměnné.

Alespoň tak to má dělat. Pokud zkopíruji výše uvedený kód a vložím jej do okna VBA IDE, velikost písmen identifikátorů se stane konzistentní a chyby runtime se náhle projeví:

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

Implementace:Je to opravdu ten nejlepší přístup?

Umm, ne. Nechápejte mě špatně. Opravdu se mi líbí myšlenka automatické změny velkých písmen v identifikátorech, aby byla zachována konzistence. Moje jediná skutečná stížnost je, že změna je provedena u každého identifikátoru s tímto jménem v celém projektu. Mnohem lepší by bylo změnit velká písmena pouze u těch identifikátorů, které odkazují na stejnou „věc“ (ať už je tato „věc“ funkce, pod, vlastnost, proměnná atd.).

Tak proč to takhle nefunguje? Očekávám, že vývojáři VBA IDE souhlasí s mým pohledem na to, jak by to mělo fungovat. Existuje však velmi dobrý důvod proč IDE takto nefunguje. Jedním slovem výkon.

Bohužel existuje pouze jeden spolehlivý způsob, jak zjistit, které identifikátory se stejným názvem ve skutečnosti odkazují na stejnou věc:analyzovat každý řádek kódu. To je sloooowwwww. To je z mé strany více než jednoduchá hypotéza. Projekt Rubberduck VBA ve skutečnosti dělá přesně toto; analyzuje každý řádek kódu v projektu, takže může provádět automatizovanou analýzu kódu a spoustu dalších skvělých věcí.

Projekt je nepochybně těžký. Pravděpodobně to funguje skvěle pro projekty Excel. Bohužel jsem nikdy nebyl natolik trpělivý, abych to použil v žádném ze svých projektů Access. Rubberduck VBA je technicky působivý projekt, ale je to také varovný příběh. Respektování rozsahu při změně velikosti písmen pro identifikátory by bylo hezké mít, ale ne na úkor současného neuvěřitelně rychlého výkonu IDE VBA.

Závěrečné myšlenky

Chápu motivaci této funkce. Myslím, že dokonce chápu, proč je implementován tak, jak je. Ale je to pro mě ten nejnepříjemnější vtip z VBA.

Pokud bych mohl vývojovému týmu Office VBA dát jediné doporučení, bylo by to nabídnout nastavení v IDE pro zakázání automatických změn velkých a malých písmen. Aktuální chování může zůstat ve výchozím nastavení povoleno. Ale pro pokročilé uživatele, kteří se snaží integrovat se systémy správy verzí, by toto chování mohlo být zcela zakázáno, aby se předešlo obtěžujícím „změnám kódu“ znečišťujícím historii revizí.


  1. Neuspořádané výsledky v SQL

  2. 2 způsoby, jak odstranit duplicitní řádky v SQLite

  3. Zkontrolujte, kolik poštovních položek je ve frontě v databázové poště na serveru SQL (T-SQL)

  4. SQLite DROP VIEW