Risoluzione dei problemi relativi ai tipi di dati (Visual Basic)

Questa pagina elenca alcuni problemi comuni che possono verificarsi quando si eseguono operazioni sui tipi di dati intrinseci.

Floating-Point le espressioni non vengono confrontate come uguali

Quando si utilizzano numeri a virgola mobile (tipo di dati singolo e tipo di dati Double), tenere presente che vengono archiviati come frazioni binarie. Ciò significa che non possono contenere una rappresentazione esatta di qualsiasi quantità che non sia una frazione binaria (della forma k / (2 ^ n) dove k e n sono numeri interi). Ad esempio, 0,5 (= 1/2) e 0,3125 (= 5/16) possono essere mantenuti come valori precisi, mentre 0,2 (= 1/5) e 0,3 (= 3/10) possono essere solo approssimazioni.

A causa di questa inesattezza, non è possibile basarsi sui risultati esatti quando si opera su valori a virgola mobile. In particolare, due valori teoricamente uguali potrebbero avere rappresentazioni leggermente diverse.

Per confrontare le quantità a virgola mobile
1. Calcolare il valore assoluto della differenza usando il Abs metodo della Math classe nello spazio dei System nomi .
2. Determinare una differenza massima accettabile, in modo da poter considerare le due quantità uguali per scopi pratici se la differenza non è maggiore.
3. Confrontare il valore assoluto della differenza con la differenza accettabile.

Nell'esempio seguente viene illustrato sia un confronto errato che corretto di due Double valori.

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))

Nell'esempio precedente viene utilizzato il ToString metodo della Double struttura in modo che possa specificare una precisione migliore rispetto all'uso della CStr parola chiave . Il valore predefinito è 15 cifre, ma il formato "G17" lo estende a 17 cifre.

L'operatore Mod non restituisce un risultato accurato

A causa dell'inesattezza dell'archiviazione a virgola mobile, l'operatore Mod può restituire un risultato imprevisto quando almeno uno degli operandi è a virgola mobile.

Il tipo di dati Decimal non utilizza la rappresentazione a virgola mobile. Molti numeri che sono inesattivi in Single e Double sono esatti in Decimal (ad esempio 0,2 e 0,3). Anche se l'aritmetica è più lenta rispetto a quella in Decimal virgola mobile, potrebbe essere utile ridurre le prestazioni per ottenere una maggiore precisione.

Per trovare il resto intero delle quantità a virgola mobile
1. Dichiarare le variabili come Decimal.
2. Usare il carattere D di tipo letterale per forzare i valori letterali Decimalin , nel caso in cui i valori siano troppo grandi per il Long tipo di dati.

Nell'esempio seguente viene illustrata la potenziale imprecisione degli operandi a virgola mobile.

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))

Nell'esempio precedente viene utilizzato il ToString metodo della Double struttura in modo che possa specificare una precisione migliore rispetto all'uso della CStr parola chiave . Il valore predefinito è 15 cifre, ma il formato "G17" lo estende a 17 cifre.

Poiché zeroPointTwo è Double, il relativo valore per 0,2 è una frazione binaria ripetuta all'infinito con un valore archiviato pari a 0,20000000000000001. Dividendo 2,0 per questa quantità restituisce 9,99999999999999999955 con un resto di 0,199999999999999999999999999991.

Nell'espressione per decimalRemainder, il carattere di tipo letterale D forza entrambi gli operandi in Decimale 0,2 ha una rappresentazione precisa. Pertanto, l'operatore Mod restituisce il resto previsto di 0,0.

Si noti che non è sufficiente dichiarare decimalRemainder come Decimal. È anche necessario forzare i valori letterali in Decimaloppure usano Double per impostazione predefinita e decimalRemainder ricevono lo stesso valore non accurato di doubleRemainder.

Il tipo booleano non viene convertito in tipo numerico in modo accurato

I valori booleani del tipo di dati non vengono archiviati come numeri e i valori archiviati non devono essere equivalenti ai numeri. Per la compatibilità con le versioni precedenti, Visual Basic fornisce parole chiave di conversione (funzione CType, CBool, CInte così via) per la conversione tra Boolean tipi numerici e . Tuttavia, altri linguaggi talvolta eseguono queste conversioni in modo diverso, come i metodi di .NET Framework.

Non è mai consigliabile scrivere codice che si basa su valori numerici equivalenti per True e False. Quando possibile, è necessario limitare l'utilizzo delle Boolean variabili ai valori logici per i quali sono progettati. Se è necessario combinare Boolean e valori numerici, assicurarsi di comprendere il metodo di conversione selezionato.

Conversione in Visual Basic

Quando si usano le CType parole chiave di conversione o CBool per convertire i tipi di dati numerici in Boolean, 0 diventa False e tutti gli altri valori diventano True. Quando si convertono Boolean valori in tipi numerici usando le parole chiave di conversione, False diventa 0 e True diventa -1.

Conversione nel framework

Il ToInt32 metodo della Convert classe nello System spazio dei nomi converte True in +1.

Se è necessario convertire un Boolean valore in un tipo di dati numerico, prestare attenzione al metodo di conversione usato.

Il valore letterale carattere genera l'errore del compilatore

In assenza di caratteri di tipo, Visual Basic presuppone i tipi di dati predefiniti per i valori letterali. Il tipo predefinito per un valore letterale carattere, racchiuso tra virgolette (" ") , è String.

Il String tipo di dati non si estende al tipo di dati Char. Ciò significa che se si vuole assegnare un valore letterale a una Char variabile, è necessario eseguire una conversione verso un tipo più piccolo o forzare il valore letterale al Char tipo.

Per creare un valore letterale Char da assegnare a una variabile o a una costante
1. Dichiarare la variabile o la costante come Char.
2. Racchiudere il valore del carattere tra virgolette (" ").
3. Seguire le virgolette doppie di chiusura con il carattere C di tipo letterale per forzare il valore letterale in Char. Ciò è necessario se l'opzione di controllo dei tipi (istruzione Option Strict) è Oned è consigliabile in ogni caso.

Nell'esempio seguente vengono illustrate sia le assegnazioni non riuscite che le assegnazioni di un valore letterale a una Char variabile.

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")

Esiste sempre un rischio nell'uso di conversioni di tipo narrowing, perché possono avere esito negativo in fase di esecuzione. Ad esempio, una conversione da String a Char può avere esito negativo se il String valore contiene più di un carattere. Pertanto, è preferibile programmare l'uso del C carattere di tipo.

Conversione di stringhe non riuscita in fase di esecuzione

Il tipo di dati String partecipa a pochissime conversioni di tipo widening. Stringsi estende solo a se stesso e solo e (una Char matrice) si estende a String.Char()CharObject Ciò è dovuto al fatto String che le variabili e le costanti possono contenere valori che altri tipi di dati non possono contenere.

Quando l'opzione di controllo dei tipi (istruzione Option Strict) è On, il compilatore non consente tutte le conversioni implicite di tipo narrowing. Sono inclusi quelli che coinvolgono String. Il codice può comunque usare parole chiave di conversione, CStr ad esempio e la funzione CType, che indirizzano .NET Framework a tentare la conversione.

Nota

L'errore di conversione di tipo narrowing viene eliminato per le conversioni dagli elementi di una For Each…Next raccolta alla variabile di controllo del ciclo. Per altre informazioni ed esempi, vedere la sezione "Conversioni strette" in For Each... Istruzione successiva.

Protezione della conversione ridotta

Lo svantaggio delle conversioni di tipo narrowing è che possono avere esito negativo in fase di esecuzione. Ad esempio, se una String variabile contiene elementi diversi da "True" o "False", non può essere convertito in Boolean. Se contiene caratteri di punteggiatura, la conversione in qualsiasi tipo numerico ha esito negativo. A meno che non si sappia che la String variabile contiene sempre valori che il tipo di destinazione può accettare, non è consigliabile provare una conversione.

Se è necessario eseguire la conversione da String a un altro tipo di dati, la procedura più sicura consiste nel racchiudere la conversione tentata in Try... Prendere... Istruzione Finally. In questo modo è possibile gestire un errore di runtime.

Matrici di caratteri

Un singolo Char oggetto e una matrice di Char elementi vengono entrambi ampliati a String. Tuttavia, String non si estende a Char(). Per convertire un String valore in una Char matrice, è possibile usare il ToCharArray metodo della System.String classe .

Valori senza significato

In generale, String i valori non sono significativi in altri tipi di dati e la conversione è altamente artificiale e pericolosa. Quando possibile, è necessario limitare l'utilizzo delle String variabili alle sequenze di caratteri per cui sono progettate. Non scrivere mai codice che si basa su valori equivalenti in altri tipi.

Vedi anche