Desenvolvimento - Visual Basic .NET
.Net Framework Inside : On Error Resume Next (Anjo ou Demónio)?
On Error Resume Next sempre foi utilizado largamente. Mas, por traz desta facilidade existe ou não um demónio que pode assombrar as aplicações? Este artigo entra no cerne da questão para responder a esta pergunta.
por Guilherme Bacellar MoralezFalando francamente, eu já fui um programador 100% de VB, e confesso que paguei meus estudos universitários com ASP, VB6 e VB.NET.
Durante meu amadurecimento profissional conheci o C#.NET e uma das coisas que mais me incomodaram foi o fato do C# não possuir a diretiva (On Error Resume Next).
Na minha humilde opinião o (On Error Resume Next) é uma diretiva de emergência em casos de problemas indesejados.
O que isso faz?
Para responder a esta pergunta, temos de pensar em situações críticas.
Vamos usar um pouco de imaginação e pensar em um login de usuários de uma loja de e-commerce.
O login vai funcionando muito bem até que um dia temos a indesejada tela de erro quando qualquer usuário tenta realizar o login.
Então, temos duas possíveis vertentes de ação:
1. Parar e entender o erro, corrigir o problema e alterar em produção.
2. Dar um jeito.
Mesmo eu admito que, por mais que a 1º opção seja absolutamente correta, em situações tão críticas quanto essas (e elas existem sim!) nós torcemos para que um (On Error Resume Next) funcione.
Então, a primeira coisa que fazemos é tentar usar. Se funcionar é lucro e o problema está resolvido :-)
Porque não usar?
Além do óbvio motivo de que usar uma declarativa destas é admitir que não sabemos programar corretamente e/ou admitir que não conseguimos achar o erro em nossa aplicação, existe a questão da performance.
SIM!!!!!!!!!!!!!!!!!!!!!
Você está lendo certo. Quando usamos o (On Error Resume Next) em uma aplicação VB.NET, mesmo que o código esteja 1000% correto, teremos um GRANDE problema de performance e vou provar isso abaixo.
Como forma de exemplo, utilizaremos uma função de demonstração com vários pontos de erro possíveis, principalmente dentro de um loop:
Function ContaCaracteresNumericos(ByVal entrada As String) As Integer
" Cria as Variaveis
Dim qtdCaracteres As Integer = 0
Dim entradaChar As Char()
" Quebra a Entrada em Caracteres
entradaChar = entrada.ToCharArray()
" Looping nos Elementos para Verificar se TODOS são Numeros
For i As Integer = 0 To entradaChar.Length - 1
" Converte para Numero
Dim tmpNumero As Integer = entradaChar(i).ToString()
" Verifica se é Maior que Zero
If (tmpNumero > 0) Then
" Soma no Contador
qtdCaracteres = qtdCaracteres + 1
End If
Next
" Retorna Total
Return qtdCaracteres
End Function
Na outra ponta, precisamos analisar o código que o compilador do VB.NET gera, então para isso usaremos o sempre útil Reflector.
Public Shared Function ContaCaracteresNumericos(ByVal entrada As String) As Integer
Dim qtdCaracteres As Integer = 0
Dim entradaChar As Char() = entrada.ToCharArray
Dim VB$t_i4$L0 As Integer = (entradaChar.Length - 1)
Dim i As Integer = 0
Do While (i <= VB$t_i4$L0)
If (Conversions.ToInteger(entradaChar(i).ToString) > 0) Then
qtdCaracteres += 1
End If
i += 1
Loop
Return qtdCaracteres
End Function
Podemos observar que não há nada de incomum além das otimizações naturais que esperamos de um compilador Microsoft.
Até agora sem segredos, então, passemos a utilizar o (On Error Resume Next):
Function ContaCaracteresNumericos(ByVal entrada As String) As Integer
" Set Performance = Ruim
On Error Resume Next
" Cria as Variaveis
Dim qtdCaracteres As Integer = 0
Dim entradaChar As Char()
" Quebra a Entrada em Caracteres
entradaChar = entrada.ToCharArray()
" Looping nos Elementos para Verificar se TODOS são Numeros
For i As Integer = 0 To entradaChar.Length - 1
" Converte para Numero
Dim tmpNumero As Integer = entradaChar(i).ToString()
" Verifica se é Maior que Zero
If (tmpNumero > 0) Then
" Soma no Contador
qtdCaracteres = qtdCaracteres + 1
End If
Next
" Retorna Total
Return qtdCaracteres
End Function
E o código gerado?
Public Shared Function ContaCaracteresNumericos(ByVal entrada As String) As Integer
Dim ContaCaracteresNumericos As Integer
Dim VB$ResumeTarget As Integer
Try
Dim VB$CurrentStatement As Integer
Label_0001:
Dim VB$ActiveHandler As Integer = -2
Label_000A:
VB$CurrentStatement = 2
Dim qtdCaracteres As Integer = 0
Label_000F:
VB$CurrentStatement = 3
Dim entradaChar As Char() = entrada.ToCharArray
Label_0019:
VB$CurrentStatement = 4
Dim VB$t_i4$L0 As Integer = (entradaChar.Length - 1)
Dim i As Integer = 0
goto Label_005C
Label_0027:
VB$CurrentStatement = 5
Dim tmpNumero As Integer = Conversions.ToInteger(entradaChar(i).ToString)
Label_003D:
VB$CurrentStatement = 6
If (tmpNumero <= 0) Then
goto Label_0053
End If
Label_004B:
VB$CurrentStatement = 7
qtdCaracteres += 1
Label_0053:
VB$CurrentStatement = 9
i += 1
Label_005C:
If (i <= VB$t_i4$L0) Then
goto Label_0027
End If
Label_0065:
VB$CurrentStatement = 10
ContaCaracteresNumericos = qtdCaracteres
goto Label_0102
Label_0079:
VB$ResumeTarget = 0
Select Case (VB$ResumeTarget + 1)
Case 1
goto Label_0001
Case 2
goto Label_000A
Case 3
goto Label_000F
Case 4
goto Label_0019
Case 5
goto Label_0027
Case 6
goto Label_003D
Case 7
goto Label_004B
Case 8, 9
goto Label_0053
Case 10
goto Label_0065
Case 11
goto Label_0102
Case Else
goto Label_00F7
End Select
Label_00B7:
VB$ResumeTarget = VB$CurrentStatement
Select Case IIf((VB$ActiveHandler > -2), VB$ActiveHandler, 1)
Case 0
goto Label_00F7
Case 1
goto Label_0079
End Select
Catch obj1 As Object When (?)
ProjectData.SetProjectError(DirectCast(obj1, Exception))
goto Label_00B7
End Try
Label_00F7:
Throw ProjectData.CreateProjectError(-2146828237)
Label_0102:
If (VB$ResumeTarget <> 0) Then
End If
Return ContaCaracteresNumericos
End Function
Analisando o código gerado com um pouco mais de atenção, podemos observar que, além da quantidade de linhas de código ter aumentado consideravelmente (o que é óbvio), o loop desapareceu e foi trocado por instruções GOTO e todas as linhas de código ganharam overhead de código (outras linhas).
Aqueles que desejam ter o deleite de analisar o resultado com C#, segue o código abaixo:
public static int ContaCaracteresNumericos(string entrada)
{
int ContaCaracteresNumericos;
int VB$ResumeTarget;
try
{
int VB$CurrentStatement;
Label_0001:
ProjectData.ClearProjectError();
int VB$ActiveHandler = -2;
Label_000A:
VB$CurrentStatement = 2;
int qtdCaracteres = 0;
Label_000F:
VB$CurrentStatement = 3;
char[] entradaChar = entrada.ToCharArray();
Label_0019:
VB$CurrentStatement = 4;
int VB$t_i4$L0 = entradaChar.Length - 1;
int i = 0;
goto Label_005C;
Label_0027:
VB$CurrentStatement = 5;
int tmpNumero = Conversions.ToInteger(entradaChar[i].ToString());
Label_003D:
VB$CurrentStatement = 6;
if (tmpNumero <= 0)
{
goto Label_0053;
}
Label_004B:
VB$CurrentStatement = 7;
qtdCaracteres++;
Label_0053:
VB$CurrentStatement = 9;
i++;
Label_005C:
if (i <= VB$t_i4$L0)
{
goto Label_0027;
}
Label_0065:
VB$CurrentStatement = 10;
ContaCaracteresNumericos = qtdCaracteres;
goto Label_0102;
Label_0079:
VB$ResumeTarget = 0;
switch ((VB$ResumeTarget + 1))
{
case 1:
goto Label_0001;
case 2:
goto Label_000A;
case 3:
goto Label_000F;
case 4:
goto Label_0019;
case 5:
goto Label_0027;
case 6:
goto Label_003D;
case 7:
goto Label_004B;
case 8:
case 9:
goto Label_0053;
case 10:
goto Label_0065;
case 11:
goto Label_0102;
default:
goto Label_00F7;
}
Label_00B7:
VB$ResumeTarget = VB$CurrentStatement;
switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
{
case 0:
goto Label_00F7;
case 1:
goto Label_0079;
}
}
catch (object obj1) when (?)
{
ProjectData.SetProjectError((Exception) obj1);
goto Label_00B7;
}
Label_00F7:
throw ProjectData.CreateProjectError(-2146828237);
Label_0102:
if (VB$ResumeTarget != 0)
{
ProjectData.ClearProjectError();
}
return ContaCaracteresNumericos;
}
A que conclusão chegamos?
Vou encerrando o artigo por aqui e fica uma reflexão:
“Vale a pena tudo isso pela comodidade do código continuar a executar mesmo dando erro?”
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET