Muitas pessoas que decidem aprender uma linguagem de programação como VB .NET ou C# geralmente não atentam para a importância de compreender os tipos de dados suportados e a forma correta de usá-los. No caso do VB .NET a atenção deveria ser redobrada visto que muitos estão migrando do VB5 ou VB6 para o VB .NET e houve alterações importantes que se não forem consideradas podem dar muita dor de cabeça no futuro.
Eu vou simular um cenário para mostrar que um pequeno detalhe pode afetar , dependendo do ambiente, o comportamento esperado por um programa.
Vamos supor que um programador trabalhando para uma instituição financeira é encarregado de criar um módulo para tratar o saldo de operações em um determinado tipo de conta onde o cliente que possui um saldo positivo poderá programar amortizações ou retiradas programadas até zerar o saldo.
Assim, se a conta possui um saldo de 100.00 ele poderá efetuar amortizações/retiradas em parcelas mensais; por exemplo 10 parcelas de R$ 10,00 até o saldo final ser igual a zero. Se o saldo for negativo o programa não poderá permitir retirada/amortização. Com isso definido vamos ao código que o programador usou:
Usando o Visual Basic 2008 Express Edition vamos criar um projeto chamado DoubleNet e no formulário form1.vb vamos definir o seguinte layout:
Como estamos usando um ListBox para exibir o resultado o código final associado ao evento Click do botão – Simular 10 Retiradas – é o seguinte:
Vamos agora verificar se a lógica esta correta testando executando o programa e fazendo alguns testes:
a) Teste com saldo inicial igual a R$ 100,00 e parcela igual a R$ 10,00
O resultado confere e parece que tudo esta correto.
Vamos agora testar com um saldo atual igual a 150,50 e parcela de 15,05. Estaremos esperando 10 retiradas de R$ 15,05 , correto ???
Executando o projeto iremos obter:
O resultado foi uma surpresa , não é mesmo ???
Veja que na décima retirada o saldo é um valor muito pequeno mas diferente de zero e assim foi permitido uma nova retirada. Uma catástrofe…
Mas qual o erro estamos cometendo? Erro de lógica? Erro de cálculo?
Nada disso o erro esta nas seguintes linhas de código :
Dim seuSaldo As Double = txtSaldo.Text
Dim parcela As Double = txtParcela.Text
Mas Onde?
O programador definiu as variável como sendo do tipo Double que suporta uma precisão numérica muito grande assim na décima parcela retirada o saldo é um número muito pequeno ( 3,552713678805 elevado a -15) que devido a precisão do tipo de dados usado é levado em conta e computado.
Dessa forma o saldo não é menor que zero permitindo assim uma nova retirada.
Desta forma um pequeno detalhe poderia dar uma grande dor de cabeça.
Um Double possui um tamanho de 8 bytes e atua no intervalo de : -1.79769313486231E308 até -4.94065645841247E-324
Como resolver o problema não permitindo que a diferença seja computada?
Conselho : No VB .NET para efetuar cálculos com valores monetários devemos usar o tipo Decimal.
No VB6 havia o tipo Currency que era usado para cálculos financeiros mas no VB .NET ele não existe e foi substituído pelo tipo Decimal.
Se você pretende continuar usando o VB6 a sugestão é não usar o tipos de dados Currency , use o tipo de dados Decimal no VB6 e no VB .NET use o tipo de dados Decimal ou Long
Além desta alteração temos abaixo uma tabela comparando o tipo de dados usado no VB6 e o atualmente usado no VB .NET:
Para usar o tipo de dados Decimal no VB6 você pode declarar a variável como Variant e usar a função cDec para convertê-la para Decimal.
Conselho : A regra de ouro é sempre declarar as variáveis entes de usá-las. (Nunca use Option Explicit Off)
A opção Option Strict é nova no VB.NET ; usando a opção Option Strict evitamos os erros em tempo de execução que se originam de conversões automáticas de variáveis.
Assim , na conversão de uma variável do tipo Int32 para o tipo Int16 ocorre um estreitamento que pode ou não dar certo pois podem existir valores que ao serem convertidos para int16 percam a precisão. Se você trabalhar com a opção Option Strict desativada , o VB vai deixar você tentar, se der certo muito bem se não der …
Vamos a um exemplo :
O código abaixo trabalha com a opção Option Strict desativada :
O VB não vai reclamar e não indicará erro neste código seu projeto vai rodar bem até que você tente fazer a conversão de um número maior que 32.767 , ai sim vai ocorrer um erro na sua aplicação…
Se ativarmos a opção Option Strict o código fica assim :
Com a opção Option Strict ativada , a coisa muda de figura. Durante a fase de projeto o VB.NET irá sublinhar o código e será gerado um erro em tempo de compilação. O VB.NET não permite a você usar o código sem fazer a modificação explícita (manual) . Você é avisado em tempo e pode ajustar o seu código.
Conselho : Use Option Explicit e Option Strict sempre ativas !
Tanto o VB.NET como C# são linguagens fortemente tipadas (como Java), isto significa que o compilador verifica por compatibilidades de tipos em tempo de execução em quase todos os casos , impedindo atribuições incompatíveis , proibindo atribuições questionáveis e fornecendo casts quando a compatibilidade de um tipo puder ser determinada apenas em tempo de execução.
Algumas conversões ocorrem automaticamente, sem você ter que se preocupar. Por padrão no VB.NET o castingé automático quando você atribui objetos a variáveis. Os objetos são então convertidos à força para o tipo da variável. Este comportamento pode ser influenciado pelas declarações:
- Option Strict On – (padrão) – o casting é restrito é não é automático
- Option Strict Off – permite conversões implícitas no seu código
Para realizar um casting explícito (conversão forçada) podemos usar o operador Ctype() ou DirectCast()
Dim Q As Object = 2.37 ' Requer Option Strict Off.
Dim I As Integer = CType(Q, Integer) ' Funciona
Dim J As Integer = DirectCast(Q, Integer) ' Falha[/comando]
Explicando: O tipo de Q em tempo de execução é Double .
Como você pode converter Double para Integer , Ctype funciona.
DirectCast Falha porque o tipo de Q em tempo de execução Não é Integer.
Ambas as palavras chaves tomam uma expressão a ser convertida como primeiro argumento e o tipo a converter como segundo argumento.
Se não houver uma conversão definida entre o tipo de dados da expressão e o tipo especificado a ser convertido tanto Ctype como DirectCast não irão funcionar. Tanto Ctype como DirectCast lançam a exceção InvalidCastException.
A função CType opera em dois argumentos. A primeira é a expressão a ser convertido, e o segundo é a classe tipo ou objeto de dados de destino. Observe que o primeiro argumento deve ser uma expressão, não um tipo. CType é uma função in-line, que significa que o código compilado faz a conversão, com freqüência sem gerar um chamada de função. Isso melhora o desempenho.
Vejamos a seguir as principais funções de conversão no VB .NET:
Nota:
- Se a expressão submetida a função estiver fora do intervalo do tipo de dados para o qual você quer converter ocorrerá um erro
- Usamos estas funções para forçar que o resultado de uma operação seja de um tipo particular diferente do resultado padrão. Assim usamos CDec para forçar para decimal em casos no qual a precisão simples, dupla ou um valor inteiro normalmente iria ocorrer.
- Se o valor fracionário submetido for exatamente 0.5 , CInt e CLng irão arredondar para o número par mais próximo. Assim 0,5 será arredondado para 0 e 1.5 será arredondado para 2.
- CDate reconhece o formato de datas de acordo com a configuração local do sistema. Você deve informar o dia , mês e ano na ordem correta de acordo com a configuração local.
Agora o último conselho: “Quem avisa amigo é…“
Até o próximo artigo…