VBA - Typmismatchning (körtidsfel 13)

Vad är ett typmatchningsfel?

Ett felmeddelande kan ofta uppstå när du kör din VBA -kod. Felet kommer att stoppa din kod från att köras helt och flagga med hjälp av en meddelanderuta som detta fel måste sorteras ut

Observera att om du inte har testat koden helt innan distribution till användare kommer detta felmeddelande att synas för användare och orsaka stor förtroende för ditt Excel -program. Tyvärr gör användare ofta väldigt märkliga saker med en applikation och är ofta saker som du som utvecklare aldrig övervägde.

Ett typmatchningsfel uppstår eftersom du har definierat en variabel med Dim -satsen som en viss typ, t.ex. heltal, datum och din kod försöker tilldela variabeln ett värde som inte är acceptabelt t.ex. textsträng tilldelad en heltalsvariabel som i detta exempel:

Här är ett exempel:

Klicka på Debug och den felande kodraden markeras med gult. Det finns inget alternativ på popup-fönstret för fel att fortsätta, eftersom detta är ett stort fel och det inte finns något sätt att koden kan köras vidare.

I det här fallet är lösningen att ändra Dim -satsen till en variabeltyp som fungerar med det värde som du tilldelar variabeln. Koden fungerar om du ändrar variabeltypen till 'String', och du skulle förmodligen också vilja ändra variabelnamnet.

Om du ändrar variabeltyp måste dock ditt projekt återställas, och du måste köra din kod igen från början igen, vilket kan vara mycket irriterande om ett långt förfarande är inblandat

Felaktig matchning orsakad av kalkylblad för kalkylblad

Exemplet ovan är mycket enkelt hur ett felmatchningsfel kan uppstå och i det här fallet kan det enkelt åtgärdas

Orsaken till felaktiga fel är dock vanligtvis mycket djupare än detta och är inte så uppenbar när du försöker felsöka din kod.

Anta som ett exempel att du har skrivit kod för att plocka upp ett värde i en viss position på ett kalkylblad och den innehåller ett beräkningsberoende andra celler i arbetsboken (B1 i detta exempel)

Arbetsbladet ser ut som det här exemplet, med en formel för att hitta ett visst tecken i en textsträng

Ur användarens synvinkel är cell A1 fritt format och de kan ange vilket värde de vill. Formeln letar dock efter en förekomst av tecknet 'B', och i det här fallet hittas det inte så cell B1 har ett felvärde.

Testkoden nedan ger ett felaktigt fel eftersom ett felaktigt värde har matats in i cell A1

1234 Sub TestMismatch ()Dim MyNumber som heltalMyNumber = Sheets ("Sheet1"). Range ("B1"). VärdeAvsluta Sub

Värdet i cell B1 har orsakat ett fel eftersom användaren har skrivit in text i cell A1 som inte överensstämmer med vad som förväntades och inte innehåller tecknet 'B'

Koden försöker tilldela värdet till variabeln 'MyNumber' som har definierats att förvänta sig ett heltal, och så får du ett felaktigt fel.

Detta är ett av dessa exempel där minutiös kontroll av din kod inte ger svaret. Du måste också titta på kalkylbladet där värdet kommer ifrån för att ta reda på varför detta händer.

Problemet finns faktiskt på kalkylbladet och formeln i B1 måste ändras så att felvärden hanteras. Du kan göra detta genom att använda "IFERROR" -formeln för att ange ett standardvärde på 0 om söktecknet inte hittas

Du kan sedan införliva kod för att kontrollera om det finns ett nollvärde och för att visa ett varningsmeddelande för användaren att värdet i cell A1 är ogiltigt

12345678 Sub TestMismatch ()Dim MyNumber som heltalMyNumber = Sheets ("Sheet1"). Range ("B1"). TextOm MyNumber = 0 DåMsgBox "Värde i cell A1 är ogiltigt", vbCriticalAvsluta SubAvsluta omAvsluta Sub

Du kan också använda datavalidering (gruppen Dataverktyg på fliken Data i menyfliksområdet) på kalkylarket för att stoppa användaren att göra vad de vill och orsaka fel i kalkylbladet i första hand. Låt dem bara ange värden som inte orsakar kalkylfel.

Du kan skriva VBA -kod baserat på ändringshändelsen i kalkylbladet för att kontrollera vad som har angetts.

Lås och lösenordsskydda även kalkylbladet så att ogiltiga data inte kan matas in

Felaktig matchning orsakad av inmatade cellvärden

Felaktiga fel kan orsakas i din kod genom att ta in normala värden från ett kalkylblad (icke-fel), men där användaren har angett ett oväntat värde t.ex. ett textvärde när du väntade dig ett tal. De kan ha bestämt sig för att infoga en rad inom ett antal nummer så att de kan sätta en anteckning i en cell som förklarar något om numret. När allt kommer omkring har användaren ingen aning om hur din kod fungerar och att de precis har kastat ut det hela genom att skriva in sin anteckning.

Exempelkoden nedan skapar en enkel matris som kallas "MyNumber" definierad med heltalsvärden

Koden itererar sedan genom ett cellintervall från A1 till A7 och tilldelar cellvärdena i matrisen med hjälp av en variabel "Coun" för att indexera varje värde

När koden når textvärdet orsakas ett felmatchningsfel av detta och allt stannar

Genom att klicka på "Debug" i fel popup-fönstret ser du kodraden som har problemet markerat med gult. Genom att hålla muspekaren över valfri instans av variabeln "Coun" i koden kommer du att kunna se värdet på "Coun" där koden har misslyckats, vilket i detta fall är 5

Om du tittar på kalkylbladet ser du att 5th cell down har textvärdet och detta har fått koden att misslyckas

Du kan ändra din kod genom att sätta in ett villkor som kontrollerar ett numeriskt värde först innan cellvärdet läggs till i matrisen

12345678910111213 Sub TestMismatch ()Dim MyNumber (10) As Integer, Coun As IntegerRäkna = 1DoOm Coun = 11 Avsluta GörIf IsNumeric (Sheets ("sheet1"). Cells (Coun, 1). Value) ThenMyNumber (Coun) = Sheets ("sheet1"). Celler (Coun, 1) .VärdeAnnanMyNumber (Coun) = 0Avsluta omCoun = Coun + 1SlingaAvsluta Sub

Koden använder "IsNumeric" -funktionen för att testa om värdet faktiskt är ett tal, och om det är det går det in i matrisen. Om det inte är tal anger det värdet noll.

Detta säkerställer att matrisindex hålls i linje med cellradnumren i kalkylarket.

Du kan också lägga till kod som kopierar det ursprungliga felvärdet och platsinformation till ett "Fel" -arkblad så att användaren kan se vad de har gjort fel när koden körs.

Det numeriska testet använder hela koden för cellen såväl som koden för att tilldela värdet till matrisen. Du kan hävda att detta bör tilldelas en variabel för att inte fortsätta upprepa samma kod, men problemet är att du skulle behöva definiera variabeln som en "variant" vilket inte är det bästa att göra.

Du behöver också datavalidering på kalkylbladet och lösenordsskydda kalkylbladet. Detta förhindrar att användaren infogar rader och anger oväntade data.

Felaktigt felmeddelande orsakas av att en funktion eller delrutin anropas med parametrar

När en funktion anropas skickar du vanligtvis parametrar till funktionen med hjälp av datatyper som redan definierats av funktionen. Funktionen kan vara en som redan är definierad i VBA, eller det kan vara en användardefinierad funktion som du har byggt själv. En delrutin kan också ibland kräva parametrar

Om du inte håller fast vid konventionerna om hur parametrarna skickas till funktionen får du ett felmeddelande

12345678 Sub CallFunction ()Dim Ret As IntegerRet = MyFunction (3, "test")Avsluta SubFunktion MyFunction (N som heltal, T som sträng) Som strängMyFunction = TAvsluta funktion

Det finns flera möjligheter här för att få ett felaktigt fel

Returvariabeln (Ret) definieras som ett heltal, men funktionen returnerar en sträng. Så snart du kör koden kommer den att misslyckas eftersom funktionen returnerar en sträng, och detta kan inte gå in i en heltalsvariabel. Intressant nog, att köra Debug på den här koden tar inte upp det här felet.

Om du sätter citattecken runt den första parametern som skickas (3) tolkas den som en sträng, som inte matchar definitionen av den första parametern i funktionen (heltal)

Om du gör den andra parametern i funktionsanropet till ett numeriskt värde misslyckas det med en felaktig matchning eftersom den andra parametern i strängen är definierad som en sträng (text)

Felaktig matchning orsakas av felaktig användning av konverteringsfunktioner i VBA

Det finns ett antal konverteringsfunktioner som du kan använda i VBA för att konvertera värden till olika datatyper. Ett exempel är 'CInt' som konverterar en sträng som innehåller ett tal till ett heltal.

Om strängen som ska konverteras innehåller några alfatecken så får du ett felaktigt fel, även om den första delen av strängen innehåller numeriska tecken och resten är alfatecken t.ex. "123abc"

Allmänt förebyggande av felaktiga fel

Vi har sett i exemplen ovan flera sätt att hantera potentiella felaktiga fel i din kod, men det finns ett antal andra sätt, även om de kanske inte är de bästa alternativen:

Definiera dina variabler som Varianttyp

En varianttyp är standardtypen variabel i VBA. Om du inte använder en Dim -sats för en variabel och helt enkelt börjar använda den i din kod, ges den automatiskt typen av variant.

En variantvariabel accepterar alla typer av data, oavsett om det är ett heltal, långt heltal, dubbelprecisionsnummer, booleskt eller textvärde. Det här låter som en underbar idé, och du undrar varför alla inte bara ställer in alla sina variabler till variant.

Variantdatatypen har dock flera nackdelar. För det första tar det mycket mer minne än andra datatyper. Om du definierar en mycket stor array som variant kommer den att svälja en enorm mängd minne när VBA -koden körs och kan lätt orsaka prestandaproblem

För det andra är det långsammare i prestanda i allmänhet än om du använder specifika datatyper. Om du till exempel gör komplexa beräkningar med flytande decimaltal blir beräkningarna betydligt långsammare om du lagrar siffrorna som varianter, snarare än dubbla precisionsnummer

Att använda varianttyp anses vara slarvig programmering, såvida det inte är absolut nödvändigt för det.

Använd kommandot OnError för att hantera fel

OnError-kommandot kan inkluderas i din kod för att hantera felinställning, så att om ett fel någonsin uppstår kan användaren se ett meningsfullt meddelande istället för standard VBA-fel

1234567 Sub ErrorTrap ()Dim MyNumber som heltalVid fel GoTo Err_HandlerMyNumber = "test"Err_Handler:MsgBox "Felet" & Err.Description & "har inträffat"Avsluta Sub

Detta förhindrar effektivt att felet stoppar en smidig körning av din kod och gör att användaren kan återhämta sig rent från felsituationen.

Err_Handler -rutinen kan visa ytterligare information om felet och vem du ska kontakta om det.

Från en programmeringssynpunkt, när du använder en felhanteringsrutin, är det ganska svårt att hitta kodraden som felet är på. Om du går igenom koden med F8, så snart den felande kodraden körs, hoppar den till felhanteringsrutinen och du kan inte kontrollera var den går fel.

En väg runt detta är att ställa in en global konstant som är sant eller falskt (booleskt) och använda detta för att aktivera eller inaktivera felhanteringsrutinen med hjälp av ett "Om" -uttalande. När du vill testa felet är allt du behöver göra att ställa in den globala konstanten till False och felhanteraren fungerar inte längre.

1 Global Const ErrHandling = Falskt
1234567 Sub ErrorTrap ()Dim MyNumber som heltalOm ErrHandling = True Då på fel Gå till Err_HandlerMyNumber = "test"Err_Handler:MsgBox "Felet" & Err.Description & "har inträffat"Avsluta Sub

Det enda problemet med detta är att det tillåter användaren att återhämta sig från felet, men resten av koden i delrutinen körs inte, vilket kan få enorma konsekvenser senare i programmet

Med det tidigare exemplet på att slinga genom ett cellintervall skulle koden komma till cell A5 och träffa det felaktiga felet. Användaren skulle se en meddelanderuta med information om felet, men ingenting från den cellen och framåt i intervallet skulle bearbetas.

Använd OnError -kommandot för att undertrycka fel

Detta använder kommandot 'On Error Resume Next'. Detta är mycket farligt att inkludera i din kod eftersom det förhindrar att eventuella efterfel visas. Detta betyder i princip att när din kod körs, om ett fel uppstår i en kodrad, körs körningen bara till nästa tillgängliga rad utan att utföra felraden och fortsätter som vanligt.

Detta kan reda ut en potentiell felsituation, men det kommer fortfarande att påverka alla framtida fel i koden. Du kanske då tror att din kod är buggfri, men det är det faktiskt inte och delar av din kod gör inte vad du tycker att den borde göra.

Det finns situationer där det är nödvändigt att använda det här kommandot, till exempel om du tar bort en fil med kommandot 'Kill' (om filen inte finns finns det ett fel), men felinställningen bör alltid bytas tillbaka omedelbart efter där det potentiella felet kan uppstå med:

1 Vid fel Gå till 0

I det tidigare exemplet på looping genom ett cellintervall, med "On Error Resume Next", skulle detta göra det möjligt för loopen att fortsätta, men cellen som orsakade felet skulle inte överföras till arrayen och arrayelementet för det specifika indexet skulle ha ett nollvärde.

Konvertera data till en datatyp för att matcha deklarationen

Du kan använda VBA -funktioner för att ändra datatypen för inkommande data så att den matchar datatypen för den mottagande variabeln.

Du kan göra detta när du skickar parametrar till funktioner. Om du till exempel har ett nummer som finns i en strängvariabel och du vill skicka det som ett tal till en funktion kan du använda CInt

Det finns ett antal av dessa konverteringsfunktioner som kan användas, men här är de viktigaste:

CInt - konverterar en sträng som har ett numeriskt värde (under + eller - 32 768) till ett heltal. Tänk på att detta avkortar alla decimaler

CLng - Konverterar en sträng som har ett stort numeriskt värde till ett långt heltal. Decimalpunkten avkortas.

CDbl - Konverterar en sträng som håller ett flytande decimaltal till ett dubbel precisionstal. Inkluderar decimaler

CDate - Konverterar en sträng som innehåller ett datum till en datumvariabel. Beror delvis på inställningarna i Windows kontrollpanel och din lokal för hur datumet tolkas

CStr - Konverterar ett numeriskt värde eller datumvärde till en sträng

Vid konvertering från en sträng till ett nummer eller ett datum får strängen inte innehålla något annat än siffror eller ett datum. Om det finns alfatecken finns det ett felmeddelande. Här är ett exempel som ger ett felaktigt fel:

123 Deltest ()MsgBox CInt ("123abc")Avsluta Sub

Testa variabler inom din kod

Du kan testa en variabel för att ta reda på vilken datatyp det är innan du tilldelar den till en variabel av en viss typ.

Till exempel kan du kontrollera en sträng för att se om den är numerisk med hjälp av funktionen 'IsNumeric' i VBA

1 MsgBox IsNumeric ("123test")

Den här koden returnerar False eftersom strängen börjar med numeriska tecken, men den innehåller också text så att testet misslyckas.

1 MsgBox IsNumeric ("123")

Denna kod kommer att returnera True eftersom det är alla numeriska tecken

Det finns ett antal funktioner i VBA att testa för olika datatyper, men dessa är de viktigaste:

IsNumeric - testar om ett uttryck är ett tal eller inte

IsDate - testar om ett uttryck är ett datum eller inte

IsNull - testar om ett uttryck är null eller inte. Ett nollvärde kan bara sättas in i ett variantobjekt annars får du ett felmeddelande "Ogiltig användning av null". En meddelanderuta returnerar ett nollvärde om du använder det för att ställa en fråga, så returvariabeln måste vara en variant. Tänk på att varje beräkning med ett nollvärde alltid kommer att returnera resultatet av null.

IsArray - testar om uttrycket representerar en array eller inte

IsEmpty - testar om uttrycket är tomt eller inte. Observera att tomt inte är detsamma som null. En variabel är tom när den först definieras men den är inte ett nollvärde

Överraskande nog finns det ingen funktion för IsText eller IsString, vilket skulle vara riktigt användbart

Objekt och felaktiga fel

Om du använder objekt som ett område eller ett ark får du ett felmeddelande vid kompileringstid, inte vid körning, vilket ger dig en varning om att din kod inte fungerar

123456 Sub TestRange ()Dim MyRange As Range, I As LongStäll in MyRange = Range ("A1: A2")Jag = 10x = UseMyRange (I)Avsluta Sub
12 Funktionsanvändning MyRange (R As Range)Avsluta funktion

Denna kod har en funktion som kallas 'UseMyRange' och en parameter som skickas över som ett intervallobjekt. Parametern som överförs är dock ett långt heltal som inte matchar datatypen.

När du kör VBA -kod kompileras den omedelbart och du får se detta felmeddelande:

Den felaktiga parametern kommer att markeras med en blå bakgrund

Generellt, om du gör misstag i VBA -kod med hjälp av objekt kommer du att se detta felmeddelande, snarare än ett typfelmeddelande:

Du kommer att bidra till utvecklingen av webbplatsen, dela sidan med dina vänner

wave wave wave wave wave