O que é um erro de incompatibilidade de tipo?
Freqüentemente, pode ocorrer um erro de incompatibilidade ao executar o código VBA. O erro impedirá que o seu código seja executado completamente e sinalizará por meio de uma caixa de mensagem que este erro precisa ser resolvido
Observe que, se você não testou totalmente seu código antes da distribuição aos usuários, essa mensagem de erro ficará visível para os usuários e causará uma grande perda de confiança em seu aplicativo Excel. Infelizmente, os usuários costumam fazer coisas muito peculiares em um aplicativo e são coisas que você, como desenvolvedor, nunca considerou.
Um erro de incompatibilidade de tipo ocorre porque você definiu uma variável usando a instrução Dim como um determinado tipo, por exemplo, inteiro, data e seu código está tentando atribuir um valor à variável que não é aceitável, por exemplo, string de texto atribuída a uma variável inteira como neste exemplo:
Aqui está um exemplo:
Clique em Debug e a linha de código incorreta será destacada em amarelo. Não há opção no pop-up de erro para continuar, já que esse é um erro grave e não há como o código continuar a ser executado.
Nesse caso específico, a solução é alterar a instrução Dim para um tipo de variável que funcione com o valor que você está atribuindo à variável. O código funcionará se você alterar o tipo de variável para ‘String’ e provavelmente também deseja alterar o nome da variável.
No entanto, a alteração do tipo de variável exigirá a redefinição do projeto, e você terá que executar o código novamente desde o início, o que pode ser muito irritante se um longo procedimento estiver envolvido
Erro de incompatibilidade causado pelo cálculo da planilha
O exemplo acima é muito simples de como um erro de incompatibilidade pode ser produzido e, neste caso, é facilmente corrigido
No entanto, a causa dos erros de incompatibilidade é geralmente muito mais profunda do que isso e não é tão óbvia quando você está tentando depurar seu código.
Por exemplo, suponha que você tenha escrito um código para coletar um valor em uma determinada posição em uma planilha e contém um cálculo dependente de outras células da planilha (B1 neste exemplo)
A planilha se parece com este exemplo, com uma fórmula para encontrar um caractere específico em uma string de texto
Do ponto de vista do usuário, a célula A1 é um formato livre e ele pode inserir qualquer valor que desejar. No entanto, a fórmula está procurando uma ocorrência do caractere ‘B’ e, neste caso, ele não foi encontrado, portanto a célula B1 tem um valor de erro.
O código de teste abaixo produzirá um erro de incompatibilidade porque um valor incorreto foi inserido na célula A1
1234 | Sub TestMismatch ()Dim MyNumber As IntegerMyNumber = Sheets ("Sheet1"). Range ("B1"). ValueEnd Sub |
O valor na célula B1 produziu um erro porque o usuário inseriu um texto na célula A1 que não está de acordo com o que era esperado e não contém o caractere 'B'
O código tenta atribuir o valor à variável ‘MyNumber’ que foi definida para esperar um número inteiro e, portanto, você obtém um erro de incompatibilidade.
Este é um desses exemplos em que verificar meticulosamente seu código não fornecerá a resposta. Você também precisa olhar na planilha de onde o valor está vindo para descobrir por que isso está acontecendo.
O problema está realmente na planilha e a fórmula em B1 precisa ser alterada para que os valores de erro sejam tratados. Você pode fazer isso usando a fórmula ‘IFERROR’ para fornecer um valor padrão de 0 se o caractere de pesquisa não for encontrado
Você pode então incorporar o código para verificar se há um valor zero e para exibir uma mensagem de aviso ao usuário de que o valor na célula A1 é inválido
12345678 | Sub TestMismatch ()Dim MyNumber As IntegerMyNumber = Sheets ("Sheet1"). Range ("B1"). TextSe MyNumber = 0 ThenMsgBox "O valor na célula A1 é inválido", vbCriticalSair do SubFim seEnd Sub |
Você também pode usar a validação de dados (grupo Ferramentas de Dados na guia Dados da faixa de opções) na planilha para impedir o usuário de fazer o que quiser e causar erros na planilha em primeiro lugar. Permita apenas que eles insiram valores que não causarão erros na planilha.
Você pode escrever o código VBA com base no evento Change na planilha para verificar o que foi inserido.
Além disso, bloqueie e proteja a planilha com senha, de modo que os dados inválidos não possam ser inseridos
Erro de incompatibilidade causado por valores de células inseridos
Erros de incompatibilidade podem ser causados em seu código trazendo valores normais de uma planilha (sem erro), mas onde o usuário inseriu um valor inesperado. um valor de texto quando você esperava um número. Eles podem ter decidido inserir uma linha dentro de um intervalo de números para que possam colocar uma nota em uma célula explicando algo sobre o número. Afinal, o usuário não tem ideia de como seu código funciona e que acabou de estragar tudo ao digitar sua nota.
O código de exemplo abaixo cria uma matriz simples chamada ‘MyNumber’ definida com valores inteiros
O código, então, itera através de um intervalo de células de A1 a A7, atribuindo os valores das células à matriz, usando uma variável ‘Contagem’ para indexar cada valor
Quando o código atinge o valor do texto, um erro de incompatibilidade é causado por isso e tudo pára
Ao clicar em ‘Depurar’ no pop-up de erro, você verá a linha de código com o problema destacado em amarelo. Ao passar o cursor sobre qualquer instância da variável ‘Coun’ dentro do código, você poderá ver o valor de ‘Coun’ onde o código falhou, que neste caso é 5
Olhando na planilha, você verá que os 5º célula abaixo tem o valor de texto e isso fez com que o código falhe
Você pode alterar seu código colocando uma condição que verifica um valor numérico antes de adicionar o valor da célula na matriz
12345678910111213 | Sub TestMismatch ()Dim MyNumber (10) como inteiro, contar como inteiroContagem = 1FazerSe Contar = 11 Então Saia FaçaIf IsNumeric (Sheets ("sheet1"). Cells (Coun, 1) .Value) ThenMyNumber (Coun) = Sheets ("sheet1"). Cells (Coun, 1) .ValueOutroMyNumber (contagem) = 0Fim seContagem = Contagem + 1CicloEnd Sub |
O código usa a função ‘IsNumeric’ para testar se o valor é realmente um número e, se for, ele o insere na matriz. Se não for um número, ele insere o valor zero.
Isso garante que o índice da matriz seja mantido em linha com os números das linhas das células na planilha.
Você também pode adicionar o código que copia o valor do erro original e os detalhes do local em uma planilha de "Erros" para que o usuário possa ver o que fez de errado quando o código for executado.
O teste numérico usa o código completo para a célula, bem como o código para atribuir o valor ao array. Você pode argumentar que isso deve ser atribuído a uma variável para não repetir o mesmo código, mas o problema é que você precisaria definir a variável como uma ‘Variante’, o que não é a melhor coisa a fazer.
Você também precisa de validação de dados na planilha e para proteger a planilha com senha. Isso evitará que o usuário insira linhas e dados inesperados.
Erro de incompatibilidade causado pela chamada de uma função ou sub-rotina usando parâmetros
Quando uma função é chamada, você geralmente passa parâmetros para a função usando tipos de dados já definidos pela função. A função pode ser uma já definida no VBA ou pode ser uma função definida pelo usuário que você mesmo criou. Uma sub-rotina às vezes também pode exigir parâmetros
Se você não seguir as convenções de como os parâmetros são passados para a função, você obterá um erro de incompatibilidade
12345678 | Sub CallFunction ()Dim Ret As IntegerRet = MyFunction (3, "teste")End SubFunção MyFunction (N As Integer, T As String) As StringMyFunction = TFunção Final |
Existem várias possibilidades aqui para obter um erro de incompatibilidade
A variável de retorno (Ret) é definida como um inteiro, mas a função retorna uma string. Assim que você executar o código, ele falhará porque a função retorna uma string e isso não pode ir para uma variável inteira. Curiosamente, a execução de Debug neste código não detecta esse erro.
Se você colocar aspas ao redor do primeiro parâmetro sendo passado (3), ele será interpretado como uma string, que não corresponde à definição do primeiro parâmetro na função (inteiro)
Se você transformar o segundo parâmetro na chamada de função em um valor numérico, ele falhará com uma incompatibilidade porque o segundo parâmetro na string é definido como uma string (texto)
Erro de incompatibilidade causado pelo uso incorreto de funções de conversão no VBA
Existem várias funções de conversão que você pode usar no VBA para converter valores em vários tipos de dados. Um exemplo é ‘CInt’, que converte uma string contendo um número em um valor inteiro.
Se a string a ser convertida contiver qualquer caractere alfa, você obterá um erro de incompatibilidade, mesmo se a primeira parte da string contiver caracteres numéricos e o resto for caracteres alfa, por exemplo, ‘123abc’
Prevenção geral de erros de incompatibilidade
Vimos nos exemplos acima várias maneiras de lidar com possíveis erros de incompatibilidade em seu código, mas existem várias outras maneiras, embora possam não ser as melhores opções:
Defina suas variáveis como tipo de variante
Um tipo de variante é o tipo de variável padrão no VBA. Se você não usar uma instrução Dim para uma variável e simplesmente começar a usá-la em seu código, ela receberá automaticamente o tipo de Variant.
Uma variável Variant aceitará qualquer tipo de dado, seja um inteiro, inteiro longo, número de precisão dupla, booleano ou valor de texto. Parece uma ideia maravilhosa, e você se pergunta por que nem todos definem todas as suas variáveis como variantes.
No entanto, o tipo de dados variante tem várias desvantagens. Em primeiro lugar, ele ocupa muito mais memória do que outros tipos de dados. Se você definir um array muito grande como variante, ele consumirá uma grande quantidade de memória quando o código VBA estiver em execução e poderá facilmente causar problemas de desempenho
Em segundo lugar, geralmente é mais lento no desempenho do que se você estiver usando tipos de dados específicos. Por exemplo, se você estiver fazendo cálculos complexos usando números decimais flutuantes, os cálculos serão consideravelmente mais lentos se você armazenar os números como variantes, em vez de números de precisão dupla
Usar o tipo de variante é considerado uma programação desleixada, a menos que haja uma necessidade absoluta para isso.
Use o comando OnError para lidar com erros
O comando OnError pode ser incluído em seu código para lidar com a interceptação de erros, de modo que, se ocorrer um erro, o usuário verá uma mensagem significativa em vez do pop-up de erro VBA padrão
1234567 | Sub ErrorTrap ()Dim MyNumber As IntegerOn Error GoTo Err_HandlerMyNumber = "teste"Err_Handler:MsgBox "O erro" & Err.Description & "ocorreu"End Sub |
Isso evita efetivamente que o erro interrompa o bom funcionamento do código e permite que o usuário se recupere de forma limpa da situação de erro.
A rotina Err_Handler pode mostrar mais informações sobre o erro e quem contatar a respeito.
Do ponto de vista da programação, quando você está usando uma rotina de tratamento de erros, é muito difícil localizar a linha de código em que o erro está. Se você estiver percorrendo o código usando F8, assim que a linha de código incorreta for executada, ela irá para a rotina de tratamento de erros e você não poderá verificar onde está errado.
Uma maneira de contornar isso é configurar uma constante global que seja True ou False (Boolean) e usar isso para ativar ou desativar a rotina de tratamento de erros usando uma instrução 'If'. Quando quiser testar o erro, tudo o que você precisa fazer é definir a constante global como False e o manipulador de erros não funcionará mais.
1 | Global Const ErrHandling = False |
1234567 | Sub ErrorTrap ()Dim MyNumber As IntegerIf ErrHandling = True Then On Error GoTo Err_HandlerMyNumber = "teste"Err_Handler:MsgBox "O erro" & Err.Description & "ocorreu"End Sub |
O único problema com isso é que permite ao usuário se recuperar do erro, mas o resto do código dentro da sub-rotina não é executado, o que pode ter enormes repercussões mais tarde no aplicativo
Usando o exemplo anterior de loop em um intervalo de células, o código chegaria à célula A5 e atingiria o erro incompatível. O usuário veria uma caixa de mensagem com informações sobre o erro, mas nada daquela célula em diante no intervalo seria processado.
Use o comando OnError para suprimir erros
Isso usa o comando ‘On Error Resume Next’. É muito perigoso incluir isso em seu código, pois evita que erros subsequentes sejam mostrados. Basicamente, isso significa que, à medida que o código está sendo executado, se ocorrer um erro em uma linha de código, a execução apenas avançará para a próxima linha disponível sem executar a linha de erro e continuará normalmente.
Isso pode resolver uma situação de erro potencial, mas ainda afetará todos os erros futuros no código. Você pode então pensar que seu código está livre de bugs, mas na verdade não está e partes de seu código não estão fazendo o que você acha que deveria estar fazendo.
Existem situações em que é necessário usar este comando, como se você estiver excluindo um arquivo usando o comando 'Kill' (se o arquivo não estiver presente, haverá um erro), mas a interceptação de erro deve sempre ser retornada imediatamente após onde o erro potencial poderia ocorrer usando:
1 | No erro, vá para 0 |
No exemplo anterior de loop em um intervalo de células, usando 'On Error Resume Next', isso permitiria que o loop continuasse, mas a célula que causou o erro não seria transferida para a matriz, e o elemento da matriz para aquele índice específico teria um valor nulo.
Converter os dados em um tipo de dados para corresponder à declaração
Você pode usar funções VBA para alterar o tipo de dados dos dados de entrada de forma que corresponda ao tipo de dados da variável de recebimento.
Você pode fazer isso ao passar parâmetros para funções. Por exemplo, se você tem um número mantido em uma variável de string e deseja passá-lo como um número para uma função, você pode usar CInt
Existem várias dessas funções de conversão que podem ser usadas, mas aqui estão as principais:
CInt - converte uma string que possui um valor numérico (abaixo de + ou - 32.768) em um valor inteiro. Esteja ciente de que isso trunca qualquer ponto decimal
CLng - Converte uma string com um grande valor numérico em um inteiro longo. Os pontos decimais são truncados.
CDbl - Converte uma string contendo um número de ponto decimal flutuante em um número de precisão dupla. Inclui pontos decimais
CDate - Converte uma string que contém uma data em uma variável de data. Depende parcialmente das configurações no Painel de controle do Windows e de sua localidade de como a data é interpretada
CStr - Converte um valor numérico ou de data em uma string
Ao converter de uma string para um número ou data, a string não deve conter nada além de números ou uma data. Se houver caracteres alfa, isso produzirá um erro de incompatibilidade. Aqui está um exemplo que produzirá um erro de incompatibilidade:
123 | Subteste ()MsgBox CInt ("123abc")End Sub |
Teste de variáveis dentro do seu código
Você pode testar uma variável para descobrir que tipo de dados ela é antes de atribuí-la a uma variável de um tipo específico.
Por exemplo, você pode verificar uma string para ver se ela é numérica usando a função ‘IsNumeric’ no VBA
1 | MsgBox IsNumeric ("123test") |
Este código retornará False porque, embora a string comece com caracteres numéricos, ela também contém texto, portanto, falha no teste.
1 | MsgBox IsNumeric ("123") |
Este código retornará True porque contém todos os caracteres numéricos
Existem várias funções no VBA para testar vários tipos de dados, mas estas são as principais:
IsNumeric - testa se uma expressão é um número ou não
IsDate - testa se uma expressão é uma data ou não
IsNull - testa se uma expressão é nula ou não. Um valor nulo só pode ser colocado em um objeto variante, caso contrário, você receberá um erro ‘Uso inválido de nulo’. Uma caixa de mensagem retorna um valor nulo se você a estiver usando para fazer uma pergunta, portanto, a variável de retorno deve ser uma variante. Lembre-se de que qualquer cálculo com valor nulo sempre retornará o resultado de nulo.
IsArray - testa se a expressão representa uma matriz ou não
IsEmpty - testa se a expressão está vazia ou não. Observe que vazio não é o mesmo que nulo. Uma variável está vazia quando é definida pela primeira vez, mas não é um valor nulo
Surpreendentemente, não há função para IsText ou IsString, o que seria muito útil
Objetos e erros de incompatibilidade
Se você estiver usando objetos como um intervalo ou uma planilha, você obterá um erro de incompatibilidade no tempo de compilação, não no tempo de execução, o que lhe dá o devido aviso de que seu código não vai funcionar
123456 | Sub TestRange ()Dim MyRange As Range, I As LongDefinir MyRange = Range ("A1: A2")I = 10x = UseMyRange (I)End Sub |
12 | Função UseMyRange (R As Range)Função Final |
Este código tem uma função chamada ‘UseMyRange’ e um parâmetro passado como um objeto de intervalo. No entanto, o parâmetro que está sendo passado é um número inteiro longo que não corresponde ao tipo de dados.
Quando você executa o código VBA, ele é compilado imediatamente e você verá esta mensagem de erro:
O parâmetro ofensivo será destacado com um fundo azul
Geralmente, se você cometer erros no código VBA usando objetos, verá esta mensagem de erro, em vez de uma mensagem de incompatibilidade de tipo: