.NET

24 jul, 2008

Usando tipos de dados corretamente

Publicidade

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 Offpermite 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:

  1. 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
  2. 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.
  3. 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.
  4. 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…