VBA - Neshoda typu (chyba běhu 13)

Co je chyba neshody typu?

Při spuštění kódu VBA může často dojít k chybě nesouladu. Chyba způsobí, že se váš kód úplně nespustí, a nahlásí jej pomocí okna se zprávou, že tuto chybu je třeba vyřešit

Všimněte si toho, že pokud jste svůj kód před distribucí uživatelům plně netestovali, tato chybová zpráva bude viditelná pro uživatele a způsobí velkou ztrátu důvěry ve vaši aplikaci Excel. Uživatelé bohužel aplikaci často dělají velmi zvláštní věci a často jde o věci, o kterých jste jako vývojář nikdy neuvažovali.

Dochází k chybě neshody typu, protože jste definovali proměnnou pomocí příkazu Dim jako určitý typ, např. celé číslo, datum a váš kód se pokouší přiřadit proměnné hodnotu, která není přijatelná, např. textový řetězec přiřazený celočíselné proměnné jako v tomto příkladu:

Zde je příklad:

Klikněte na Debug a problematický řádek kódu se zvýrazní žlutě. Ve vyskakovacím okně s chybou nelze pokračovat, protože se jedná o závažnou chybu a neexistuje způsob, jak by kód mohl dále běžet.

V tomto konkrétním případě je řešením změnit příkaz Dim na typ proměnné, který pracuje s hodnotou, kterou proměnné přiřazujete. Kód bude fungovat, pokud změníte typ proměnné na „String“ a pravděpodobně budete chtít změnit také název proměnné.

Změna typu proměnné však bude vyžadovat reset vašeho projektu a budete muset znovu spustit kód hned od začátku, což může být velmi nepříjemné, pokud jde o dlouhý postup

Neshoda Chyba způsobená výpočtem listu

Výše uvedený příklad je velmi jednoduchým příkladem toho, jak lze vytvořit chybu nesouladu, a v tomto případě ji lze snadno opravit

Příčina neshodných chyb je však obvykle mnohem hlubší a není tak zřejmá, když se pokoušíte ladit kód.

Předpokládejme například, že jste napsali kód pro vyzvednutí hodnoty na určité pozici na listu a obsahuje další buňky závislé na výpočtu v sešitu (v tomto případě B1)

List vypadá jako v tomto příkladu se vzorcem pro nalezení konkrétního znaku v řetězci textu

Z pohledu uživatele je buňka A1 volného formátu a může zadat libovolnou hodnotu, kterou chce. Vzorec však hledá výskyt znaku „B“ a v tomto případě není nalezen, takže buňka B1 má chybovou hodnotu.

Níže uvedený testovací kód způsobí chybu nesouladu, protože do buňky A1 byla zadána nesprávná hodnota

1234 Nesoulad dílčích testů ()Dim MyNumber As IntegerMyNumber = Sheets ("Sheet1"). Range ("B1"). ValueEnd Sub

Hodnota v buňce B1 způsobila chybu, protože uživatel zadal do buňky A1 text, který neodpovídá tomu, co se očekávalo, a neobsahuje znak „B“

Kód se pokusí přiřadit hodnotu proměnné ‘MyNumber’, která byla definována tak, aby očekávala celé číslo, a tak se zobrazí chyba nesouladu.

Toto je jeden z těchto příkladů, kde pečlivá kontrola kódu neposkytne odpověď. Musíte se také podívat na pracovní list, odkud hodnota pochází, abyste zjistili, proč se to děje.

Problém je ve skutečnosti na listu a vzorec v B1 je třeba změnit, aby byly zpracovány chybové hodnoty. To lze provést pomocí vzorce „IFERROR“ k zadání výchozí hodnoty 0, pokud není hledaný znak nalezen

Poté můžete začlenit kód, abyste zkontrolovali nulovou hodnotu a uživateli zobrazili varovnou zprávu, že hodnota v buňce A1 je neplatná

12345678 Nesoulad dílčích testů ()Dim MyNumber As IntegerMyNumber = Sheets ("Sheet1"). Range ("B1"). TextPokud MyNumber = 0 ThenMsgBox "Hodnota v buňce A1 je neplatná", vbCriticalUkončit dílčíKonec IfEnd Sub

Můžete také použít ověření dat (skupina Datové nástroje na kartě Data na pásu karet) v tabulce, aby uživatel nemohl dělat, co se mu zlíbí, a na prvním místě způsobit chyby v listu. Umožněte jim pouze zadat hodnoty, které nezpůsobí chyby v listu.

Můžete napsat kód VBA na základě události Change v listu a zkontrolovat, co bylo zadáno.

Pracovní list chrání také zámek a heslo, takže nelze zadat neplatná data

Neshoda Chyba způsobená zadanými hodnotami buňky

Chyby nesouladu mohou být ve vašem kódu způsobeny uvedením normálních hodnot z listu (bez chyby), ale tam, kde uživatel zadal neočekávanou hodnotu, např. textovou hodnotu, když jste očekávali číslo. Možná se rozhodli vložit řádek v rozsahu čísel, aby mohli do buňky vložit poznámku vysvětlující něco o čísle. Koneckonců, uživatel nemá tušení, jak váš kód funguje a že právě vyhodili celou věc z kilteru zadáním své poznámky.

Níže uvedený příklad kódu vytvoří jednoduché pole s názvem „MyNumber“ definované celočíselnými hodnotami

Kód pak iteruje rozsah buněk od A1 do A7, přiřazuje hodnoty buněk do pole pomocí proměnné ‘Coun’ pro indexování každé hodnoty

Když kód dosáhne textové hodnoty, je tím způsobena chyba neshody a vše se zastaví

Kliknutím na „Debug“ ve vyskakovacím okně s chybou se zobrazí řádek kódu, který má problém zvýrazněný žlutou barvou. Když umístíte kurzor na libovolnou instanci proměnné „Coun“ v kódu, uvidíte hodnotu „Coun“ v případě, že kód selhal, což je v tomto případě 5

Při pohledu na pracovní list uvidíte, že 5th buňka dolů má textovou hodnotu a to způsobilo selhání kódu

Kód můžete změnit vložením podmínky, která nejprve kontroluje číselnou hodnotu, než přidáte hodnotu buňky do pole

12345678910111213 Nesoulad dílčích testů ()Dim MyNumber (10) As Integer, Coun As IntegerPočítadlo = 1DělatPokud Coun = 11, pak Exit DoIf IsNumeric (Sheets ("sheet1"). Cells (Coun, 1) .Value) ThenMyNumber (Coun) = Sheets ("sheet1"). Cells (Coun, 1) .ValueJinýMoje číslo (Coun) = 0Konec IfCoun = Coun + 1SmyčkaEnd Sub

Kód pomocí funkce „IsNumeric“ otestuje, zda je hodnota ve skutečnosti číslem, a pokud ano, zadá ji do pole. Pokud to není číslo, zadá hodnotu nula.

Tím je zajištěno, že je index pole udržován v souladu s čísly řádků buněk v tabulce.

Můžete také přidat kód, který zkopíruje původní chybovou hodnotu a podrobnosti o umístění na list „Chyby“, aby uživatel viděl, co udělal špatně, když je váš kód spuštěn.

Numerický test používá celý kód pro buňku a také kód pro přiřazení hodnoty do pole. Můžete tvrdit, že by to mělo být přiřazeno proměnné, aby se neopakoval stejný kód, ale problém je v tom, že byste proměnnou museli definovat jako „variantu“, což není nejlepší.

Potřebujete také ověření dat na listu a ochranu listu heslem. To zabrání uživateli vkládat řádky a zadávat neočekávaná data.

Neshoda Chyba způsobená voláním funkce nebo dílčí rutiny pomocí parametrů

Při volání funkce obvykle předáváte funkci parametry pomocí datových typů, které již funkce definovala. Funkce může být jednou již definovanou ve VBA, nebo to může být funkce definovaná uživatelem, kterou jste sami vytvořili. Dílčí rutina může také někdy vyžadovat parametry

Pokud nedodržíte konvence, jak jsou parametry předávány funkci, zobrazí se chyba nesouladu

12345678 Sub CallFunction ()Dim Ret jako celé čísloRet = MyFunction (3, "test")End SubFunkce MyFunction (N jako celé číslo, T jako řetězec) jako řetězecMyFunction = TKoncová funkce

Existuje několik možností, jak získat chybu nesouladu

Návratová proměnná (Ret) je definována jako celé číslo, ale funkce vrací řetězec. Jakmile spustíte kód, selže, protože funkce vrací řetězec, a to nemůže jít do celočíselné proměnné. Je zajímavé, že spuštění ladění na tomto kódu tuto chybu nezachytí.

Pokud vložíte uvozovky kolem prvního předávaného parametru (3), bude interpretován jako řetězec, který neodpovídá definici prvního parametru ve funkci (celé číslo)

Pokud provedete druhý parametr ve volání funkce na číselnou hodnotu, selže s neshodou, protože druhý parametr v řetězci je definován jako řetězec (text)

Neshoda Chyba způsobená nesprávným použitím funkcí převodu ve VBA

Existuje celá řada funkcí převodu, které můžete ve VBA využít k převodu hodnot na různé datové typy. Příkladem je „CInt“, který převádí řetězec obsahující číslo na celočíselnou hodnotu.

Pokud řetězec, který má být převeden, obsahuje jakékoli alfa znaky, zobrazí se chyba nesouladu, i když první část řetězce obsahuje číselné znaky a zbytek jsou alfa znaky, např. „123abc“

Obecná prevence chyb nesouladu

Ve výše uvedených příkladech jsme viděli několik způsobů, jak se vypořádat s potenciálními neshodami ve vašem kódu, ale existuje řada dalších způsobů, i když nemusí být nejlepší:

Definujte své proměnné jako typ varianty

Typ varianty je výchozí typ proměnné ve VBA. Pokud pro proměnnou nepoužijete příkaz Dim a jednoduše jej začnete používat ve svém kódu, bude mu automaticky přidělen typ Variant.

Proměnná varianty bude přijímat jakýkoli typ dat, ať už jde o celé číslo, dlouhé celé číslo, číslo s dvojitou přesností, logickou hodnotu nebo textovou hodnotu. To zní jako skvělý nápad a vy se divíte, proč každý nenastaví všechny své proměnné na variantu.

Datový typ varianty má však několik stinných stránek. Za prvé, zabírá mnohem více paměti než jiné datové typy. Pokud jako variantu definujete velmi velké pole, pohltí při spuštění kódu VBA obrovské množství paměti a může snadno způsobit problémy s výkonem

Za druhé, výkon je obecně pomalejší, než když používáte konkrétní datové typy. Pokud například provádíte složité výpočty pomocí čísel s plovoucí desetinnou čárkou, výpočty budou podstatně pomalejší, pokud čísla uložíte jako varianty, nikoli jako čísla s dvojnásobnou přesností

Použití variantního typu je považováno za nedbalé programování, pokud to není absolutně nutné.

K zpracování chyb použijte příkaz OnError

Příkaz OnError může být součástí vašeho kódu, aby se vypořádal s chycením chyb, takže pokud dojde k chybě, uživatel místo standardního vyskakovacího okna chyby VBA uvidí smysluplnou zprávu

1234567 Sub ErrorTrap ()Dim MyNumber As IntegerPři chybě GoTo Err_HandlerMyNumber = "test"Err_Handler:MsgBox "Chyba" & Err.Popis & "došlo"End Sub

Tím se účinně zabrání tomu, aby chyba zastavila plynulý běh vašeho kódu, a umožňuje uživateli čistě se zotavit z chybové situace.

Rutina Err_Handler by mohla zobrazit další informace o chybě a koho na ni kontaktovat.

Z hlediska programování je při použití rutiny zpracování chyb poměrně obtížné najít řádek kódu, na kterém je chyba. Pokud procházíte kódem pomocí F8, ihned po spuštění problematického řádku kódu přejde na rutinu zpracování chyb a nemůžete zkontrolovat, kde se děje chyba.

Způsobem, jak to obejít, je nastavit globální konstantu, která je True nebo False (logická hodnota), a pomocí ní zapnout nebo vypnout rutinu zpracování chyb pomocí příkazu „If“. Pokud chcete chybu otestovat, stačí nastavit globální konstantu na hodnotu False a obsluha chyb již nebude fungovat.

1 Global Const ErrHandling = False
1234567 Sub ErrorTrap ()Dim MyNumber As IntegerIf ErrHandling = True Then On Error GoTo Err_HandlerMyNumber = "test"Err_Handler:MsgBox "Chyba" & Err.Popis & "došlo"End Sub

Jediným problémem je, že to umožňuje uživateli zotavit se z chyby, ale zbytek kódu v rámci dílčí rutiny se nespustí, což může mít později v aplikaci obrovské důsledky

Použitím dřívějšího příkladu smyčky přes rozsah buněk by se kód dostal do buňky A5 a narazil na neshodnou chybu. Uživatel by viděl okno se zprávou s informacemi o chybě, ale nic od této buňky dále v rozsahu nebude zpracováno.

K potlačení chyb použijte příkaz OnError

Používá se k tomu příkaz „On Error Resume Next“. Zahrnutí do kódu je velmi nebezpečné, protože zabraňuje zobrazování jakýchkoli následných chyb. To v podstatě znamená, že když se váš kód spouští, pokud dojde k chybě v řádku kódu, provádění se přesune na další dostupný řádek bez spuštění chybového řádku a bude pokračovat jako obvykle.

To může vyřešit potenciální chybovou situaci, ale stále to ovlivní každou budoucí chybu v kódu. Můžete si pak myslet, že váš kód neobsahuje chyby, ale ve skutečnosti tomu tak není a části vašeho kódu nedělají to, co si myslíte, že by dělat mělo.

Existují situace, kdy je nutné použít tento příkaz, například pokud odstraňujete soubor pomocí příkazu „Zabít“ (pokud soubor není k dispozici, dojde k chybě), ale odchyt chyb by měl být vždy přepnut zpět okamžitě poté, kde by k potenciální chybě mohlo dojít pomocí:

1 Při chybě Přejít na 0

V dřívějším příkladu opakování cyklu buněk pomocí 'On Error Resume Next' by to umožnilo pokračování smyčky, ale buňka způsobující chybu by nebyla přenesena do pole a prvek pole pro daný index by držel nulovou hodnotu.

Převod dat na datový typ tak, aby odpovídal deklaraci

Pomocí funkcí VBA můžete změnit datový typ příchozích dat tak, aby odpovídal datovému typu přijímající proměnné.

To lze provést při předávání parametrů funkcím. Pokud například máte číslo uložené v řetězcové proměnné a chcete jej předat funkci jako číslo, můžete použít CInt

Existuje řada těchto funkcí převodu, které lze použít, ale zde jsou hlavní:

CInt - převede řetězec, který má číselnou hodnotu (pod + nebo - 32 768) na celočíselnou hodnotu. Uvědomte si, že to zkrátí všechny desetinné čárky

CLng - Převede řetězec, který má velkou číselnou hodnotu, na dlouhé celé číslo. Desetinná místa jsou oříznuta.

CDbl - Převede řetězec obsahující číslo s plovoucí desetinnou čárkou na číslo s dvojnásobnou přesností. Zahrnuje desetinná místa

CDate - Převede řetězec, který obsahuje datum na proměnnou data. Částečně závisí na nastavení v Ovládacích panelech systému Windows a vašem národním prostředí na tom, jak je datum interpretováno

CStr - Převede číselnou hodnotu nebo hodnotu data na řetězec

Při převodu z řetězce na číslo nebo datum nesmí řetězec obsahovat nic jiného než čísla nebo datum. Pokud jsou přítomny znaky alfa, dojde k chybě nesouladu. Zde je příklad, který způsobí chybu nesouladu:

123 Dílčí test ()MsgBox CInt ("123abc")End Sub

Testování proměnných ve vašem kódu

Proměnnou můžete otestovat, abyste zjistili, o jaký datový typ se jedná, než ji přiřadíte proměnné konkrétního typu.

Můžete například zkontrolovat řetězec a zjistit, zda je číselný, pomocí funkce „IsNumeric“ ve VBA

1 MsgBox IsNumeric ("123test")

Tento kód vrátí hodnotu False, protože ačkoli řetězec začíná číselnými znaky, obsahuje také text, takže v testu neprošel.

1 MsgBox IsNumeric ("123")

Tento kód vrátí True, protože to jsou všechny číselné znaky

Ve VBA existuje řada funkcí k testování různých datových typů, ale toto jsou hlavní:

IsNumeric - testuje, zda je výraz číslo nebo ne

IsDate - testuje, zda je výraz datum nebo ne

IsNull - testuje, zda je výraz null nebo ne. Hodnotu null lze zadat pouze do objektu varianty, jinak se zobrazí chyba „Neplatné použití hodnoty Null“. Okno se zprávou vrací hodnotu null, pokud ji používáte k položení otázky, takže návratová proměnná musí být variantou. Mějte na paměti, že jakýkoli výpočet pomocí hodnoty null vždy vrátí výsledek null.

IsArray - testuje, zda výraz představuje pole nebo ne

IsEmpty - testuje, zda je výraz prázdný nebo ne. Všimněte si, že prázdný není stejný jako null. Proměnná je prázdná, když je poprvé definována, ale nejedná se o hodnotu null

Překvapivě neexistuje žádná funkce pro IsText nebo IsString, což by bylo opravdu užitečné

Objekty a chyby nesouladu

Pokud používáte objekty, jako je rozsah nebo list, zobrazí se chyba nesouladu v době kompilace, nikoli v době běhu, což vám dává náležité varování, že váš kód nebude fungovat

123456 Dílčí testovací rozsah ()Dim MyRange As Range, I As LongNastavit MyRange = rozsah ("A1: A2")I = 10x = UseMyRange (I)End Sub
12 Funkce UseMyRange (R As Range)Koncová funkce

Tento kód má funkci nazvanou „UseMyRange“ a parametr předávaný jako objekt rozsahu. Parametr, který je předáván, je však Long Integer, který neodpovídá datovému typu.

Když spustíte kód VBA, je okamžitě zkompilován a zobrazí se tato chybová zpráva:

Urážlivý parametr bude zvýrazněn na modrém pozadí

Obecně platí, že pokud uděláte chyby v kódu VBA pomocí objektů, zobrazí se tato chybová zpráva místo zprávy o neshodě typu:

wave wave wave wave wave