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

Zpracování chyb na úrovni absolventa

Dobrá skládačka mě baví stejně jako další kluk. Na tom, jak začít s hromadou zdánlivě náhodných kousků a dívat se, jak obraz pomalu ožívá, když obnovujete řád v chaosu, je něco uspokojivého.

Přestal jsem ale skládat puzzle. Už je to pravděpodobně, oh, 13 let. Nech mě to spočítat. Mám čtyři děti; nejstarší je 15.  Jo, dva roky jsou přesně v době, kdy byla dost stará na to, aby se zatoulala k nedokončenému puzzle, utekla s jedním z dílků a dala ho psovi nebo tepelnému registru nebo záchodu.

A jak uspokojivé je umístit poslední dílek do skládačky, je stejně zdrcující umístit předposlední dílek do skládačky a uvědomit si, že poslední dílek chybí.

Takhle jsem se kdysi cítil ohledně svého kódu pro zpracování chyb.

Inspektor proměnných vbWatchdog

Pokud používáte vbWatchdog pro zpracování chyb (měli byste), pak byste měli být obeznámeni s jednou z jeho nejvýkonnějších funkcí:Variables Inspector. Tento objekt poskytuje přístup ke každé proměnné v oboru na každé úrovni zásobníku volání. Tato úroveň detailů je digitální zlato, když přijde čas na odstraňování chyb.

V průběhu let jsem vyvinul pokročilý modul zpracování chyb, který všechny tyto informace zaznamenává. Když jsem dolaďoval zpracování chyb, začala vystupovat jedna skvrna. I když jsem mohl extrahovat hodnoty většiny svých proměnných, jediné, co jsem kdy mohl získat z objektových proměnných, bylo buď 'Nic' nebo '{Object}'.

To není žádné klepání na vbWatchdog. Předmětem může být cokoliv. Jakou jinou hodnotu by to mohlo vykazovat? Přesto ve mně tento chybějící kousek skládačky hlodal. Cítil jsem, jak se mi vesmír směje, když jsem odstraňoval nějakou chybu, a klíč k jejímu vyřešení se skrýval za tím jedním šíleně stydlivým slovem '{Object}'.

Kdybych jen měl nějaký způsob, jak poznat jednu nebo dvě z identifikačních vlastností tohoto objektu, mohl bych přesně zjistit, co se děje.

První pokus

Můj první pokus o vyřešení problému je nástroj každého frustrovaného programátora:hrubá síla. Do své globální obslužné rutiny chyb jsem přidal Vybrat... případ příkaz kolem .TypeDesc .

Mám například třídu SQL Builder, kterou nazývám clsSQL . Jednou z vlastností v této třídě je .LastSQL . Tato vlastnost obsahuje poslední příkaz SQL, který třída vytvořila nebo provedla. Může to být příkaz SELECT nebo INSERT/UPDATE/DELETE/atd. (Nápad jsem si vypůjčil z objektu DAL společnosti web2py. )

Zde je část mého globálního obslužného programu chyb:

Select Case .TypeDesc
Case "clsSQL"
    If Not .Value Is Nothing Then
        ThisVar = .Name & ".LastSQL = " & .Value.LastSQL
    End If

Postupem času jsem do tohoto seznamu začal přidávat další vlastní typy objektů. S každým vlastním typem bych potřeboval načíst jinou vlastní vlastnost.

Měl jsem svůj poslední kousek skládačky. Problém je v tom, že jsem to našel plavat v psí misce s vodou, celý rozžvýkaný na jedné straně. Myslím, že by se dalo říct, že moje hádanka byla kompletní, ale bylo to Pyrrhovo vítězství.

Lék, který nadělá více škody než užitku

Rychle jsem si uvědomil, že toto řešení nebude škálovatelné. Problémů bylo mnoho. Za prvé, můj globální kód pro zpracování chyb se nafoukl. Kód pro zpracování chyb uchovávám v jediném standardním modulu v rámci své knihovny kódů. To znamená, že kdykoli bych chtěl přidat podporu pro modul třídy, tento kód by se přidal do každého z mých projektů. To platilo, i když byl modul třídy použit pouze v jednom projektu.

Dalším problémem je, že jsem do svého kódu pro zpracování chyb zaváděl externí závislosti. Co kdybych změnil svůj clsSQL třídy a přejmenujte nebo odstraňte .LastSQL metoda? Jaká je šance, že bych si uvědomil, že taková závislost existovala, když jsem pracoval ve svém clsSQL třída? Tento přístup by se svou vlastní vahou rychle zhroutil, pokud bych nepřišel na alternativu.

Hledáme řešení v Pythonu

Uvědomil jsem si, že to, co jsem opravdu chtěl, byl nějaký způsob, jak určit kanonickou reprezentaci objektu z tohoto objektu . Chtěl jsem mít možnost implementovat tuto reprezentaci tak jednoduše nebo komplexně, jak je potřeba. Chtěl jsem způsob, jak zaručit, že to nevybuchne za běhu. Chtěl jsem, aby to bylo zcela nepovinné pro každý modul třídy.

Zdá se to jako dlouhý seznam přání, ale dokázal jsem uspokojit každou položku na něm řešením, které jsem našel.

Opět jsem si vypůjčil nápad z Pythonu. Všechny objekty Pythonu mají speciální vlastnost známou jako ._repr . Tato vlastnost je řetězcová reprezentace objektu. Ve výchozím nastavení vrátí název typu a adresu paměti instance objektu. Programátoři Pythonu však mohou definovat .__repr__ metoda k přepsání výchozího chování. Toto je šťavnatý kousek, který jsem chtěl pro své kurzy VBA.

Konečně jsem našel ideální řešení. Bohužel jsem to našel v jiném jazyce, kde je řešení ve skutečnosti vlastností jazyka samotného . Jak mi to má pomoci ve VBA? Ukázalo se, že důležitou součástí byl nápad; Jen jsem musel být trochu kreativní s implementací.

Rozhraní pro záchranu

Abych propašoval tento koncept Pythonu do VBA, obrátil jsem se na zřídka používanou funkci jazyka:rozhraní a operátor TypeOf. Zde je návod, jak to funguje.

Vytvořil jsem modul třídy, který jsem nazval iReprezentace . Rozhraní ve většině jazyků jsou pojmenována s počátečním „i“ podle konvence. Moduly si samozřejmě můžete pojmenovat, jak chcete. Zde je úplný kód mé iReprezentace třída.

iRepresentation.cls

`--== iRepresentation ==-- class module
Option Compare Database
Option Explicit

Public Property Get Repr() As String
End Property

Měl bych zdůraznit, že na modulu třídy, který slouží jako rozhraní ve VBA, není nic zvláštního. Tím chci říct, že neexistuje žádné klíčové slovo na úrovni modulu nebo skrytý atribut, který bychom museli nastavit. Můžeme dokonce vytvořit instanci nového objektu pomocí tohoto typu, i když by to nemělo žádný význam (výjimkou je testování, ale to je téma na jiný den). Platný kód by byl například následující:

Dim Representation As iRepresentation
Set Representation = New iRepresentation

Debug.Print Representation.Repr

Nyní řekněme, že mám vlastní modul třídy s názvem oJigsawPuzzle . Modul třídy má několik vlastností a metod, ale my chceme takovou, která nám pomůže identifikovat, se kterým objektem JigsawPuzzle máme co do činění, když dojde k chybě. Jedním z jasných kandidátů na takovou práci je SKU, které jedinečně identifikuje hlavolam jako produkt na pultech obchodů. Samozřejmě, v závislosti na naší situaci můžeme chtít do našeho zastoupení zahrnout i další informace.

oJigsawPuzzle.cls

'--== oJigsawPuzzle ==-- class module
Option Compare Database
Option Explicit

Implements iRepresentation   ' <-- We need this line...

Private mSKU As String
Private mPieceCount As Long
Private mDesigner As String
Private mTitle As String
Private mHeightInInches As Double
Private mWidthInInches As Double

'... and these three lines
Private Property Get iRepresentation_Repr() As String
    iRepresentation_Repr = mSKU
End Property

Zde přichází kouzlo.  Když se propracováváme objektem Variables Inspector, můžeme nyní otestovat každou proměnnou objektu, abychom zjistili, zda implementuje toto rozhraní. A pokud ano, můžeme tuto hodnotu uchopit a zaprotokolovat ji spolu se zbytkem hodnot našich proměnných.

Výňatek z obslužného programu chyb

' --== Global Error Handler excerpt ==--

'Include Repr property value for classes that 
'        implement the iRepresentation interface
If TypeOf .Value Is iRepresentation Then
    Dim ObjWithRepr As iRepresentation
    Set ObjWithRepr = .Value
    ThisVar = .Name & ".Repr = " & ObjWithRepr.Repr
End If

A tím je moje hádanka se zpracováním chyb dokončena. Všechny kusy jsou zaúčtovány. Nejsou žádné stopy po kousnutí. Žádný z kousků se neodlupuje. Nejsou žádná prázdná místa.

Konečně jsem obnovil pořádek v chaosu.


  1. Poddotaz SQL Server vrátil více než 1 hodnotu. To není povoleno, pokud poddotaz následuje =, !=, <, <=,>,>=

  2. Funkce BITAND() v Oracle

  3. Oracle convert unix epoch time to date

  4. Mohu použít více kurzorů na jedno připojení s pyodbc a MS SQL Server?