VBA - Несъответствие на типа (Грешка по време на работа 13)

Какво е грешка при несъответствие на типа?

Грешка при несъответствие често може да възникне, когато стартирате вашия VBA код. Грешката ще спре кода ви да работи напълно и ще се отбележи с помощта на поле за съобщение, което тази грешка се нуждае от сортиране

Имайте предвид, че ако не сте тествали напълно кода си преди разпространението му сред потребителите, това съобщение за грешка ще бъде видимо за потребителите и ще доведе до голяма загуба на доверие във вашето приложение на Excel. За съжаление, потребителите често правят много странни неща за дадено приложение и често са неща, които вие като разработчик никога не сте обмисляли.

Възниква грешка при несъответствие на типа, защото сте дефинирали променлива, използвайки оператора Dim като определен тип, напр. цяло число, дата и вашият код се опитва да присвои стойност на променливата, която не е приемлива, напр. текстов низ, присвоен на целочислена променлива, както в този пример:

Ето един пример:

Щракнете върху Отстраняване на грешки и нарушаващият ред код ще бъде маркиран в жълто. В изскачащия прозорец за грешка няма опция за продължаване, тъй като това е голяма грешка и няма начин кодът да може да работи по-нататък.

В този конкретен случай решението е да промените оператора Dim на променлив тип, който работи със стойността, която присвоявате на променливата. Кодът ще работи, ако промените типа на променливата на „String“ и вероятно бихте искали да промените и името на променливата.

Промяната на типа на променливата обаче ще се нуждае от нулиране на вашия проект и ще трябва да стартирате кода си отново от самото начало, което може да бъде много досадно, ако се включва дълга процедура

Грешка при несъответствие, причинена от изчислението на работния лист

Примерът по -горе е много прост начин за грешка при несъответствие и в този случай лесно се отстранява

Причината за грешки при несъответствие обикновено е много по -дълбока от тази и не е толкова очевидна, когато се опитвате да отстраните грешки в кода си.

Като пример, да предположим, че сте написали код, за да вземете стойност в определена позиция на работен лист и той съдържа зависими от изчисленията други клетки в работната книга (В1 в този пример)

Работният лист изглежда като този пример с формула за намиране на определен символ в низ от текст

От гледна точка на потребителя, клетка А1 е свободен формат и те могат да въведат всякаква стойност, която искат. Формулата обаче търси поява на знак „В“ и в този случай не се намира, така че клетка В1 има стойност на грешка.

Тестовият код по -долу ще доведе до грешка при несъответствие, тъй като в клетка А1 е въведена грешна стойност

1234 Sub TestMismatch ()Dim MyNumber As IntegerMyNumber = Листове ("Sheet1"). Диапазон ("B1"). СтойностEnd Sub

Стойността в клетка B1 доведе до грешка, защото потребителят е въвел текст в клетка A1, който не съответства на очакваното и не съдържа знака „B“

Кодът се опитва да присвои стойността на променливата „MyNumber“, която е определена да очаква цяло число и така получавате грешка при несъответствие.

Това е един от тези примери, при които щателната проверка на кода ви няма да даде отговор. Също така трябва да погледнете в работния лист откъде идва стойността, за да разберете защо това се случва.

Проблемът всъщност е на работния лист и формулата в B1 се нуждае от промяна, така че да се справят със стойностите на грешките. Можете да направите това, като използвате формулата „IFERROR“, за да предоставите стойност по подразбиране 0, ако знакът за търсене не е намерен

След това можете да включите код, за да проверите за нулева стойност и да покажете предупредително съобщение на потребителя, че стойността в клетка A1 е невалидна

12345678 Sub TestMismatch ()Dim MyNumber As IntegerMyNumber = Листове ("Sheet1"). Диапазон ("B1"). ТекстАко MyNumber = 0 ТогаваMsgBox "Стойността в клетка A1 е невалидна", vbCriticalИзход от SubКрай АкоEnd Sub

Можете също така да използвате валидиране на данни (група „Инструменти за данни“ в раздела „Данни“ на лентата) в електронната таблица, за да спрете потребителя да прави каквото им харесва и да причини грешки на работния лист на първо място. Позволете им да въвеждат само стойности, които няма да причинят грешки на работния лист.

Можете да напишете VBA код въз основа на събитието Change в работния лист, за да проверите въведеното.

Също така заключването и паролата защитават работния лист, така че невалидните данни да не могат да бъдат въведени

Грешка при несъответствие, причинена от въведените стойности на клетката

Грешките в несъответствието могат да бъдат причинени във вашия код чрез въвеждане на нормални стойности от работен лист (без грешка), но когато потребителят е въвел неочаквана стойност, напр. текстова стойност, когато очаквахте число. Може да са решили да вмъкнат ред в диапазон от числа, за да могат да поставят бележка в клетка, обясняваща нещо за номера. В края на краищата потребителят няма представа как работи вашият код и че току -що са изхвърлили всичко от килтър, като са въвели бележката си.

Примерният код по -долу създава прост масив, наречен „MyNumber“, дефиниран с цели числа

След това кодът итерира през диапазон от клетки от A1 до A7, като присвоява стойностите на клетката в масива, като използва променлива „Coun“ за индексиране на всяка стойност

Когато кодът достигне текстовата стойност, това причинява грешка при несъответствие и всичко се смила

Като щракнете върху „Отстраняване на грешки“ в изскачащия прозорец за грешка, ще видите реда с код, в който проблемът е маркиран в жълто. Като задържите курсора върху който и да е екземпляр на променливата „Coun“ в кода, ще можете да видите стойността на „Coun“, където кодът е неуспешен, което в този случай е 5

Разглеждайки работния лист, ще видите, че 5th клетката надолу има текстова стойност и това е причинило кода да се провали

Можете да промените кода си, като поставите първо условие, което проверява за числова стойност, преди да добавите стойността на клетката в масива

12345678910111213 Sub TestMismatch ()Dim MyNumber (10) As Integer, Coun As IntegerCoun = 1НаправетеАко Coun = 11, излезте от DoIf IsNumeric (Sheets ("sheet1"). Cells (Coun, 1). Value) ТогаваMyNumber (Coun) = Sheets ("sheet1"). Cells (Coun, 1) .ValueИначеMyNumber (Coun) = 0Край АкоCoun = Coun + 1ЦикълEnd Sub

Кодът използва функцията „IsNumeric“, за да провери дали стойността всъщност е число и ако е, тогава я въвежда в масива. Ако не е число, тогава се въвежда стойността нула.

Това гарантира, че индексът на масива се поддържа в съответствие с номерата на редовете на клетките в електронната таблица.

Можете също така да добавите код, който копира първоначалната стойност на грешката и подробностите за местоположението в работен лист „Грешки“, така че потребителят да може да види какво е направил погрешно, когато кодът ви се изпълнява.

Численият тест използва пълния код за клетката, както и кода за присвояване на стойността в масива. Можете да спорите, че това трябва да бъде присвоено на променлива, за да не се повтаря един и същ код, но проблемът е, че ще трябва да дефинирате променливата като „Вариант“, което не е най -доброто нещо за правене.

Също така се нуждаете от валидиране на данни на работния лист и за защита на работния лист с парола. Това ще попречи на потребителя да вмъква редове и да въвежда неочаквани данни.

Грешка при несъответствие, причинена от извикване на функция или подпрограма, използваща параметри

Когато се извиква функция, обикновено предавате параметри на функцията, като използвате типове данни, които вече са определени от функцията. Функцията може да е такава, която вече е дефинирана във VBA, или може да бъде функция, дефинирана от потребителя, която сте създали сами. Подпрограма може също понякога да изисква параметри

Ако не се придържате към конвенциите за това как параметрите се предават на функцията, ще получите грешка при несъответствие

12345678 Sub CallFunction ()Dim Ret като цяло числоRet = MyFunction (3, "тест")End SubФункция MyFunction (N като цяло число, T като низ) като низMyFunction = TКрайна функция

Тук има няколко възможности да получите грешка при несъответствие

Връщащата се променлива (Ret) е дефинирана като цяло число, но функцията връща низ. Веднага след като стартирате кода, той ще се провали, тъй като функцията връща низ и това не може да влезе в целочислена променлива. Интересното е, че стартирането на Debug на този код не отчита тази грешка.

Ако поставите кавички около първия предаван параметър (3), той се интерпретира като низ, който не съответства на дефиницията на първия параметър във функцията (цяло число)

Ако направите втория параметър в извикването на функция в числова стойност, той ще се провали с несъответствие, тъй като вторият параметър в низа е дефиниран като низ (текст)

Грешка при несъответствие, причинена от неправилно използване на функциите за преобразуване във VBA

Има редица функции за преобразуване, които можете да използвате във VBA, за да конвертирате стойности в различни типове данни. Пример е „CInt“, който преобразува низ, съдържащ число, в цяло число.

Ако низът, който трябва да се преобразува, съдържа алфа знаци, ще получите грешка при несъответствие, дори ако първата част на низ съдържа цифри, а останалата част е алфа знаци, напр. „123abc“

Общо предотвратяване на грешки при несъответствие

Виждали сме в горните примери няколко начина за справяне с потенциални грешки при несъответствие във вашия код, но има редица други начини, въпреки че може да не са най -добрите варианти:

Определете променливите си като тип вариант

Тип вариант е типът променлива по подразбиране във VBA. Ако не използвате оператор Dim за променлива и просто започнете да го използвате във вашия код, тогава той автоматично получава типа на варианта.

Променлива Variant ще приема всеки тип данни, независимо дали е цяло число, дълго цяло число, число с двойна точност, булева или текстова стойност. Това звучи като прекрасна идея и се чудите защо всички не просто задават всички свои променливи на вариант.

Вариантният тип данни обаче има няколко недостатъка. Първо, той заема много повече памет от другите типове данни. Ако дефинирате много голям масив като вариант, той ще погълне огромно количество памет, когато кодът VBA работи, и лесно може да причини проблеми с производителността

Второ, производителността е по -бавна, отколкото ако използвате конкретни типове данни. Например, ако правите сложни изчисления, използвайки числа с плаваща десетична запетая, изчисленията ще бъдат значително по -бавни, ако съхранявате числата като варианти, а не числа с двойна точност

Използването на варианта се счита за небрежно програмиране, освен ако няма абсолютна необходимост от това.

Използвайте командата OnError за справяне с грешки

Командата OnError може да бъде включена във вашия код, за да се справи с улавянето на грешки, така че ако някога възникне грешка, потребителят вижда смислено съобщение вместо стандартния изскачащ прозорец за грешка VBA

1234567 Sub ErrorTrap ()Dim MyNumber As IntegerПри грешка GoTo Err_HandlerMyNumber = "тест"Err_Handler:MsgBox "Грешката" & Err.Description & "възникна"End Sub

Това ефективно предотвратява грешката да спре гладкото протичане на вашия код и позволява на потребителя да се възстанови чисто от ситуацията на грешка.

Процедурата Err_Handler може да покаже допълнителна информация за грешката и към кого да се обърнем за нея.

От гледна точка на програмирането, когато използвате програма за обработка на грешки, е доста трудно да се намери редът на кода, на който е грешката. Ако преминавате през кода с помощта на F8, веднага след като се изпълни нарушителният ред на кода, той преминава към рутината за обработка на грешки и не можете да проверите къде се обърка.

Един начин да заобиколите това е да настроите глобална константа, която е True или False (Boolean) и да използвате това, за да включите или изключите рутината за обработка на грешки, като използвате оператор „If“. Когато искате да тествате грешката, всичко, което трябва да направите, е да зададете глобалната константа на False и манипулаторът на грешки вече няма да работи.

1 Global Const ErrHandling = False
1234567 Sub ErrorTrap ()Dim MyNumber As IntegerАко ErrHandling = True, тогава при грешка отидете на Err_HandlerMyNumber = "тест"Err_Handler:MsgBox "Грешката" & Err.Description & "е възникнала"End Sub

Единственият проблем с това е, че позволява на потребителя да се възстанови от грешката, но останалата част от кода в подпрограмата не се изпълнява, което може да има огромни последици по -късно в приложението

Използвайки по -ранния пример за циклично преминаване през диапазон от клетки, кодът ще стигне до клетка А5 и ще удари несъответстващата грешка. Потребителят ще види кутия със съобщения, даваща информация за грешката, но нищо от тази клетка нататък в диапазона няма да бъде обработено.

Използвайте командата OnError за потискане на грешки

Това използва командата „On Error Resume Next“. Това е много опасно да се включи във вашия код, тъй като предотвратява показването на последващи грешки. Това основно означава, че тъй като вашият код се изпълнява, ако възникне грешка в ред код, изпълнението просто ще се премести в следващия наличен ред, без да изпълнява реда за грешка, и ще продължи както обикновено.

Това може да разреши потенциална грешка, но все пак ще повлияе на всяка бъдеща грешка в кода. Тогава може да мислите, че кодът ви не съдържа грешки, но всъщност не е така и части от кода ви не правят това, което смятате, че трябва да прави.

Има ситуации, в които е необходимо да се използва тази команда, например ако изтривате файл с помощта на командата „Kill“ (ако файлът не присъства, ще има грешка), но улавянето на грешки винаги трябва да се превключи обратно на веднага след това, където потенциалната грешка може да възникне, като използвате:

1 При грешка Отидете на 0

В по -ранния пример за циклично преминаване през диапазон от клетки, използвайки „On Error Resume Next“, това би позволило цикълът да продължи, но клетката, причиняваща грешката, няма да бъде прехвърлена в масива и елемента на масива за този конкретен индекс ще съдържа нулева стойност.

Конвертиране на данните в тип данни, за да съответстват на декларацията

Можете да използвате VBA функции, за да промените типа данни на входящите данни, така че да съответства на типа данни на получаващата променлива.

Можете да направите това при предаване на параметри на функции. Например, ако имате номер, който се държи в низ от променлива и искате да го предадете като число на функция, можете да използвате CInt

Има няколко от тези функции за преобразуване, които могат да се използват, но ето основните:

CInt - преобразува низ, който има цифрова стойност (под + или - 32,768) в цяло число. Имайте предвид, че това отрязва всички десетични точки

CLng - Конвертира низ, който има голяма цифрова стойност в дълго цяло число. Десетичните точки се отрязват.

CDbl - Преобразува низ, съдържащ число с плаваща десетична запетая, в число с двойна точност. Включва десетични точки

CDate - Конвертира низ, който съдържа дата в променлива за дата. Частично зависи от настройките в контролния панел на Windows и вашия локал от начина, по който датата се тълкува

CStr - Конвертира числова или дата стойност в низ

При преобразуване от низ в число или дата, низът не трябва да съдържа нищо друго освен числа или дата. Ако има алфа знаци, това ще доведе до грешка при несъответствие. Ето пример, който ще доведе до грешка при несъответствие:

123 Подтест ()MsgBox CInt ("123abc")End Sub

Тестване на променливи във вашия код

Можете да тествате променлива, за да разберете какъв тип данни е, преди да я присвоите на променлива от определен тип.

Например, можете да проверите низ, за ​​да видите дали е цифров, като използвате функцията „IsNumeric“ във VBA

1 MsgBox IsNumeric ("123test")

Този код ще върне False, защото въпреки че низът започва с цифрови знаци, той също съдържа текст, така че не успява теста.

1 MsgBox IsNumeric ("123")

Този код ще върне True, защото всички са цифрови знаци

Във VBA има редица функции за тестване за различни типове данни, но това са основните:

IsNumeric - проверява дали изразът е число или не

IsDate - тества дали изразът е дата или не

IsNull - проверява дали изразът е нулев или не. Нулева стойност може да бъде поставена само във вариант обект, в противен случай ще получите грешка „Невалидно използване на Null“. Кутия за съобщение връща нулева стойност, ако я използвате, за да зададете въпрос, така че връщащата променлива трябва да бъде вариант. Имайте предвид, че всяко изчисление, използващо нулева стойност, винаги ще връща резултата от null.

IsArray - проверява дали изразът представлява масив или не

IsEmpty - проверява дали изразът е празен или не. Обърнете внимание, че празното не е същото като null. Променливата е празна, когато е дефинирана за първи път, но не е нулева стойност

Изненадващо, няма функция за IsText или IsString, която би била наистина полезна

Обекти и грешки при несъответствие

Ако използвате обекти като диапазон или лист, ще получите грешка при несъответствие по време на компилиране, а не по време на изпълнение, което ви предупреждава, че кодът ви няма да работи

123456 Sub TestRange ()Dim MyRange As Range, I As LongЗадайте MyRange = Range ("A1: A2")I = 10x = UseMyRange (I)End Sub
12 Функция UseMyRange (R като диапазон)Крайна функция

Този код има функция, наречена „UseMyRange“ и параметър, предаван като обект на диапазон. Параметърът, който се предава, обаче е Long Integer, който не съответства на типа данни.

Когато стартирате VBA код, той веднага се компилира и ще видите това съобщение за грешка:

Нарушаващият параметър ще бъде маркиран със син фон

Като цяло, ако правите грешки във VBA кода с помощта на обекти, ще видите това съобщение за грешка, а не съобщение за несъответствие на типа:

Така ще помогнете за развитието на сайта, сподели с приятелите си

wave wave wave wave wave