Resolução de Problemas de Tipos de Dados (Visual Basic)

Esta página lista alguns problemas comuns que podem ocorrer quando realiza operações em tipos de dados intrínsecos.

Floating-Point Expressões Não Comparam como Iguais

Quando trabalhar com números de vírgula flutuante (Tipo de Dados Único e Tipo de Dados Duplo), lembre-se de que são armazenados como frações binárias. Isto significa que não podem conter uma representação exata de qualquer quantidade que não seja uma fração binária (do formulário k / (2 ^ n) em que k e n são números inteiros). Por exemplo, 0,5 (= 1/2) e 0,3125 (= 5/16) podem ser mantidos como valores precisos, enquanto 0,2 (= 1/5) e 0,3 (= 3/10) só podem ser aproximações.

Devido a esta imprecisão, não pode depender de resultados exatos quando opera em valores de vírgula flutuante. Em particular, dois valores teoricamente iguais podem ter representações ligeiramente diferentes.

Para comparar as quantidades de vírgula flutuante
1. Calcule o valor absoluto da diferença ao utilizar o Abs método da Math classe no System espaço de nomes.
2. Determine uma diferença máxima aceitável, de modo a considerar que as duas quantidades são iguais para fins práticos se a diferença não for maior.
3. Compare o valor absoluto da diferença com a diferença aceitável.

O exemplo seguinte demonstra uma comparação incorreta e correta de dois Double valores.

Dim oneThird As Double = 1.0 / 3.0
Dim pointThrees As Double = 0.333333333333333

' The following comparison does not indicate equality.
Dim exactlyEqual As Boolean = (oneThird = pointThrees)

' The following comparison indicates equality.
Dim closeEnough As Double = 0.000000000000001
Dim absoluteDifference As Double = Math.Abs(oneThird - pointThrees)
Dim practicallyEqual As Boolean = (absoluteDifference < closeEnough)

MsgBox("1.0 / 3.0 is represented as " & oneThird.ToString("G17") &
    vbCrLf & "0.333333333333333 is represented as " &
    pointThrees.ToString("G17") &
    vbCrLf & "Exact comparison generates " & CStr(exactlyEqual) &
    vbCrLf & "Acceptable difference comparison generates " &
    CStr(practicallyEqual))

O exemplo anterior utiliza o ToString método da Double estrutura para que possa especificar uma maior precisão do que a CStr palavra-chave utiliza. A predefinição é de 15 dígitos, mas o formato "G17" expande-o para 17 dígitos.

O Operador Mod não devolve o resultado exato

Devido à imprecisão do armazenamento de vírgula flutuante, o Operador Mod pode devolver um resultado inesperado quando pelo menos um dos operandos é flutuante.

O Tipo de Dados Decimais não utiliza representação de vírgula flutuante. Muitos números que são inexatos Single e Double estão exatos em Decimal (por exemplo, 0,2 e 0,3). Embora a aritmética seja mais lenta do que em Decimal vírgula flutuante, pode valer a pena a diminuição do desempenho para obter uma maior precisão.

Para encontrar o resto inteiro das quantidades de vírgula flutuante
1. Declarar variáveis como Decimal.
2. Utilize o caráter D literal para forçar literais a Decimal, caso os respetivos valores sejam demasiado grandes para o Long tipo de dados.

O exemplo seguinte demonstra a potencial imprecisão dos operandos de vírgula flutuante.

Dim two As Double = 2.0
Dim zeroPointTwo As Double = 0.2
Dim quotient As Double = two / zeroPointTwo
Dim doubleRemainder As Double = two Mod zeroPointTwo

MsgBox("2.0 is represented as " & two.ToString("G17") &
    vbCrLf & "0.2 is represented as " & zeroPointTwo.ToString("G17") &
    vbCrLf & "2.0 / 0.2 generates " & quotient.ToString("G17") &
    vbCrLf & "2.0 Mod 0.2 generates " &
    doubleRemainder.ToString("G17"))

Dim decimalRemainder As Decimal = 2D Mod 0.2D
MsgBox("2.0D Mod 0.2D generates " & CStr(decimalRemainder))

O exemplo anterior utiliza o ToString método da Double estrutura para que possa especificar uma maior precisão do que a CStr palavra-chave utiliza. A predefinição é de 15 dígitos, mas o formato "G17" expande-o para 17 dígitos.

Como zeroPointTwo é Double, o seu valor para 0,2 é uma fração binária de repetição infinita com um valor armazenado de 0,20000000000000000001. A divisão de 2,0 por esta quantidade gera 9,9999999999999999995 com um resto de 0,1999999999999991.

Na expressão para decimalRemainder, o caráter D literal força ambos os operandos a Decimale 0,2 tem uma representação precisa. Por conseguinte, o Mod operador produz o restante esperado de 0,0.

Tenha em atenção que não é suficiente declarar decimalRemainder como Decimal. Também tem de forçar os literais a Decimal, ou estes utilizam Double por predefinição e decimalRemainder recebe o mesmo valor impreciso que doubleRemainder.

O Tipo booleano não é convertido num tipo numérico com precisão

Os valores booleanos do Tipo de Dados não são armazenados como números e os valores armazenados não se destinam a ser equivalentes a números. Para compatibilidade com versões anteriores, o Visual Basic fornece palavras-chave de conversão (Função CType, CBool, CInte assim sucessivamente) para converter entre Boolean tipos numéricos. No entanto, por vezes, outros idiomas executam estas conversões de forma diferente, assim como os métodos de .NET Framework.

Nunca deve escrever código que dependa de valores numéricos equivalentes para True e False. Sempre que possível, deve restringir a utilização de Boolean variáveis aos valores lógicos para os quais foram concebidas. Se tiver de misturar Boolean e numéricos valores, certifique-se de que compreende o método de conversão que seleciona.

Conversão no Visual Basic

Quando utiliza as CType palavras-chave de conversão ou CBool para converter tipos de dados numéricos False em Boolean, 0 torna-se e todos os outros valores tornam-se True. Quando converte Boolean valores em tipos numéricos com as palavras-chave de conversão, False torna-se 0 e True torna-se -1.

Conversão no Framework

O ToInt32 método da Convert classe no espaço de nomes converte-se True em System +1.

Se tiver de converter um Boolean valor num tipo de dados numérico, tenha cuidado com o método de conversão que utiliza.

Literal de Carateres Gera Erro do Compilador

Na ausência de qualquer tipo de carateres, o Visual Basic assume tipos de dados predefinidos para literais. O tipo predefinido para um literal de carateres , entre aspas (" ") é String.

O String tipo de dados não se alarga ao Tipo de Dados de Caráter. Isto significa que, se pretender atribuir um literal a uma Char variável, tem de fazer uma conversão de estreitamento ou forçar o literal ao Char tipo.

Para criar um literal char para atribuir a uma variável ou constante
1. Declare a variável ou constante como Char.
2. Coloque o valor do caráter entre aspas (" ").
3. Siga a aspas de fecho dupla com o caráter C de tipo literal para forçar o literal a Char. Isto é necessário se o comutador de verificação do tipo (Instrução Estrita da Opção) for On, e for desejável em qualquer caso.

O exemplo seguinte demonstra atribuições sem êxito e bem-sucedidas de um literal a uma Char variável.

Dim charVar As Char
' The following statement attempts to convert a String literal to Char.
' Because Option Strict is On, it generates a compiler error.
charVar = "Z"
' The following statement succeeds because it specifies a Char literal.
charVar = "Z"c
' The following statement succeeds because it converts String to Char.
charVar = CChar("Z")

Existe sempre o risco de utilizar conversões de restrição, uma vez que podem falhar no tempo de execução. Por exemplo, uma conversão de String para Char pode falhar se o String valor contiver mais de um caráter. Por conseguinte, é melhor programar utilizar o caráter de C tipo.

A Conversão de Cadeias falha no Tempo de Execução

O Tipo de Dados de Cadeia participa em muito poucas conversões de alargamento. String alarga-se apenas a si próprio e Object, e apenas Char e Char() (uma Char matriz) alargam-se para String. Isto deve-se ao facto String de as variáveis e as constantes poderem conter valores que outros tipos de dados não podem conter.

Quando o comutador de verificação do tipo (Instrução Estrita da Opção) for On, o compilador não permite todas as conversões de restrição implícitas. Isto inclui os que envolvem String. O código ainda pode utilizar palavras-chave de conversão, como CStr a Função CType, que direciona o .NET Framework para tentar a conversão.

Nota

O erro de conversão de restrição é suprimido para conversões dos elementos numa For Each…Next coleção para a variável de controlo de ciclo. Para obter mais informações e exemplos, veja a secção "Conversões de Restrição" em Para Cada... Instrução Seguinte.

Restringir a Proteção de Conversão

A desvantagem de restringir as conversões é que podem falhar no tempo de execução. Por exemplo, se uma String variável contiver algo diferente de "Verdadeiro" ou "Falso", não pode ser convertida em Boolean. Se contiver carateres de pontuação, a conversão para qualquer tipo numérico falhará. A menos que saiba que a variável String contém sempre valores que o tipo de destino pode aceitar, não deve tentar uma conversão.

Se tiver de converter para outro tipo de String dados, o procedimento mais seguro é incluir a conversão tentada na Tentativa... Apanhar... Por fim, Instrução. Isto permite-lhe lidar com uma falha de tempo de execução.

Matrizes de Carateres

Uma única Char e uma matriz de Char elementos alargam-se para String. No entanto, String não alarga para Char(). Para converter um String valor numa Char matriz, pode utilizar o ToCharArray método da System.String classe.

Valores Sem Sentido

Em geral, String os valores não são significativos noutros tipos de dados e a conversão é altamente artificial e perigosa. Sempre que possível, deve restringir a utilização de String variáveis às sequências de carateres para as quais foram concebidas. Nunca deve escrever código que dependa de valores equivalentes noutros tipos.

Ver também