 .NET  - 
Usando tipos de dados corretamente
 .NET  - 
Usando tipos de dados corretamente
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.
Na tabela abaixo temos os tipos de dados do VB .NET:
| Tipo de dados | tipo .NET Runtime | tamanho | intervalo | 
| 
    Boolean | 
    System.Boolean | 4 bytes | True ou False | 
| Byte | 
    System.Byte | 1 byte | 0 até 255 (sem sinal) | 
| Char | 
    System.Char | 2 bytes | 0 até 65535 (sem sinal) | 
| Date | 
    System.DateTime | 8 bytes | Janeiro 1, 1 CE até Dezembro 31, 9999 | 
| 
    Decimal | 
    System.Decimal | 12 bytes | +/-79,228,162,514,264,337,593,543,950,335 sem ponto decimal ; +/-7.9228162514264337593543950335 com 28 casas a direita do decimal; o menor valor diferente de zero é algo em torno de 0.0000000000000000000000000001 | 
| Double | 
    System.Double | 8 bytes | -1.79769313486231E308 até -4.94065645841247E-324 para valores negativos; 4.94065645841247E-324 até 1.79769313486232E308 para valores positivos; | 
| 
    Integer | 
    System.Int32 | 4 bytes | -2,147,483,648 até 2,147,483,647 | 
| Long | 
    System.Int64 | 8 bytes | -9,223,372,036,854,775,808 até 9,223,372,036,854,775,807 | 
| Object | 
    System.Object(class) | 4 bytes | Qualquer tipo pode ser armazenado. | 
| Short | 
    System.Int16 | 2 bytes | -32,768 até 32,767. | 
| Single | 
    System.Single | 4 bytes | -3.402823E38 até -1.401298E-45 para valores negativos; 1.401298E-45 até 3.402823E38 para valores positivos; | 
| String | 
    System.String(class) | 10 bytes + (2 * tamanho da string) | Até aproximadamente dois bilhões de caracteres Unicode. | 
| User-Defined Type (estrutura) | (herda de System.ValueType) | Soma dos tamanhos dos seus membros | Cada membro da estrutura possui um intervalo determinado pelo seu tipo de dados e é independente dos intervalos dos demais números; | 
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 leiaute:
|  | Controles usados 
    no formulário: 
 É definido o saldo Atual e o valor da parcela da retirada. Para simular as retiradas é usado um loop que será executado até que o saldo for maior que zero onde do valor do saldo atual será subtraído o valor da parcela; a cada interação incrementamos um contador para saber o número de retiradas que foi efetuada. Abaixo temos o trecho de código usado : WhileseuSaldo > 0      seuSaldo -= parcela End While | 
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:
| PrivateSub btnSimular_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSimular.Click 'limpamos o controle ListBox e indicamos que estamos usando um Double lstbResultado.Items.Clear() lstbResultado.Items.Add(" ---- Usando Double ----") 
 'obtemos o valor do saldo da parcela e definimos o valor da variável para contar as retiradas como sendo igual a zero Dim seuSaldo As Double = txtSaldo.Text Dim totalRetiradas As Integer = 0 Dim parcela As Double = txtParcela.Text 
 'executamo o laço While enquando o saldo for maior que zero While seuSaldo > 0 seuSaldo -= parcela     
    totalRetiradas += 1 'exibimos o total de retiradas e o saldo no ListBox lstbResultado.Items.Add("Retirou " & totalRetiradas & " parcela") lstbResultado.Items.Add("Saldo Atual: " & seuSaldo) 
    End 
    While 'Após encerrar o laço exibimos o total de retiradas lstbResultado.Items.Add("-----------------") lstbResultado.Items.Add("Vocˆ retirou " & totalRetiradas & " parcelas!") 
 End Sub | 
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 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:
| VB6 | VB.NET | Comentários | 
| Integer | Short | 16 bits | 
| Long | Integer | 32 bits | 
| N/A | Long | 64 bits | 
| Variant | N/D | Use o novo tipo de dados Object | 
| Currency | N/D | Use o Decimal no VB6 ou Decimal ou Long no VB .NET. | 
| N/D | Decimal | Disponível no VB6(converter de Variant para Decimal com a função cDec.) Nativo no VB.NET | 
| String | String | O VB.NET não suporta strings de tamanho fixo. | 
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 :
| Option Strict Off Private Sub Calculo(NumeroMaior as Int32 , NumeroMenor as Int16) Dim troca as int32 troca = NumeroMaior NumeroMenor = troca End Sub | 
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 :
| Option 
    Strict On Private Sub Calculo(NumeroMaior as Int32 , NumeroMenor as Int16) Dim troca as int32 troca = NumeroMaior NumeroMenor = troca if NumeroMaior > NumeroMenor.Value then MessageBox " Atenção ! Este número não suporta a conversão " else NumeroMenor = Ctype(troca, Int16) endif End Sub End Sub | 
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
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:
| Função | Descrição | Exemplo | 
| Cbool | Converte para um Booleano ( False ou True). False ou 0 será definido como False. Retorna um Boolean | Dim A, B, C As Integer Dim Check As Boolean A = 5 B = 5 Check = | 
| Cbyte | Converte para um Byte . Qualquer valor maior que 255 ou valor fracionário será perdido. Retorna um Byte. | Dim MyDouble As Double Dim MyByte As Byte MyDouble = 125.5678 MyByte = | 
| CChar | Converte para um Caracter . Qualquer valor maior que 65,535 será perdido e , se você tentar converter uma string somente o primeiro caractere será convertido. | Dim MyString As String Dim MyChar As Char MyString = "BCD" 'converte só o primeiro caractere MyChar = | 
| CDate | Converte para um Date. Aceita qualquer representação de data e tempo. | Dim 
    MyDateString, MyTimeString As String Dim MyDate, MyTime As Date MyDateString = "February 12, 1969" MyTimeString = "4:35:47 PM" ' ... MyDate = 
    CDate(MyDateString)' Converte p/ o tipo Date.MyTime = CDate(MyTimeString)
    ' Converte p/ o tipo Date. | 
| CDbl | Converte para um Double. | Dim MyDec As 
    Decimal Dim MyDouble As Double MyDec = 234.456784D . MyDouble = 
    CDbl(MyDec * 8.2D * 0.01D)' Converte para Double | 
| CDec | Converte para um Decimal. | Dim MyDouble 
    As Double Dim MyDecimal As Decimal MyDouble = 10000000.0587 MyDecimal = 
    CDec(MyDouble)' Converte para Decimal. | 
| CInt | Converte para um inteiro. Valores de -2,147,483,648 até 2,147,483,647 . Frações são arredondadas. | Dim MyDouble As Double Dim MyInt As Integer MyDouble = 2345.5678 MyInt = | 
| CLng | Converte para um Longo. Valores -9,223,372,036,854,775,808 até 9,223,372,036,854,775,807. Frações são arredondadas. | Dim MyDbl1, 
    MyDbl2 As Double Dim MyLong1, MyLong2 As Long MyDbl1 = 25427.45 MyDbl2 = 25427.55 MyLong1 = 
    CLng(MyDbl1)' MyLong1 conterá 25427.MyLong2 = CLng(MyDbl2)' MyLong2 conterá 25428. | 
| CSht | Converte para um Short. Valores de 32,768 a 32,767. Frações são arredondadas. | Dim MyByte 
    as Byte Dim MyShort as Short MyByte = 100 MyShort = CShort(MyByte) ' Converte para Short. | 
| CStr | converte para um String. Se for uma Data o retorno será no formato - Short Date. | Dim MyDouble As Double Dim MyString As String MyDouble = 437.324 MyString = | 
| CSng | Converte para um Single . -3.402823E+38 até -1.401298E-45 // 1.401298E-45 até 3.402823E+38 | Dim MyDouble1, MyDouble2 As Double Dim MySingle1, MySingle2 As Single MyDouble1 = 75.3421105 MyDouble2 = 75.3421567 MySingle1 = | 
| CObj | Converte para um objeto. | Dim MyDouble As Double Dim MyObject As Object MyDouble = 2.7182818284 MyObject = | 
| Ctype | Converte para qualquer tipo de dados. Sintaxe: Variavel = Ctype( TipoVelho , NovoTipo) | Dim MyNumber 
    As Long Dim MyNewType As Single MyNumber = 1000 MyNewType = CType(MyNumber,Single) ' MyNewType é igual a p/1000.0 | 
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...

Referências:
José Carlos Macoratti