Felsöka datatyper (Visual Basic)
På den här sidan visas några vanliga problem som kan uppstå när du utför åtgärder på inbyggda datatyper.
Floating-Point uttryck jämförs inte som lika med
När du arbetar med flyttalsnummer (enkel datatyp och dubbel datatyp) ska du komma ihåg att de lagras som binära bråktal. Det innebär att de inte kan innehålla en exakt representation av en kvantitet som inte är ett binärt bråk (i formatet k / (2 ^ n) där k och n är heltal). Till exempel kan 0,5 (= 1/2) och 0,3125 (= 5/16) hållas som exakta värden, medan 0,2 (= 1/5) och 0,3 (= 3/10) endast kan vara uppskattningar.
På grund av den här obeslutsamheten kan du inte förlita dig på exakta resultat när du arbetar med flyttalsvärden. I synnerhet kan två värden som teoretiskt sett är lika ha något olika representationer.
Jämföra flyttalskvantiteter |
---|
1. Beräkna det absoluta värdet för deras skillnad med hjälp Abs av metoden för Math klassen i System namnområdet. 2. Fastställ en godtagbar maximal skillnad, så att du kan betrakta de två kvantiteterna som lika för praktiska ändamål om deras skillnad inte är större. 3. Jämför det absoluta värdet för skillnaden med den godtagbara skillnaden. |
I följande exempel visas både felaktig och korrekt jämförelse av två Double
värden.
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))
I föregående exempel används ToString metoden för Double strukturen så att den kan ange bättre precision än nyckelordet CStr
använder. Standardvärdet är 15 siffror, men formatet "G17" utökar det till 17 siffror.
Mod-operatorn returnerar inte korrekt resultat
På grund av obeslutsamheten i flyttalslagringen kan modoperatorn returnera ett oväntat resultat när minst en av operanderna är flyttal.
Decimaldatatypen använder inte flyttalsrepresentation. Många tal som är inexakta i Single
och Double
är exakta i Decimal
(till exempel 0,2 och 0,3). Även om aritmetiken är långsammare i Decimal
än i flyttal kan det vara värt prestandaminskningen för att uppnå bättre precision.
Så här hittar du heltalsmängden av flyttalskvantiteter |
---|
1. Deklarera variabler som Decimal .2. Använd literaltypstecknet D för att tvinga literaler till Decimal , om deras värden är för stora för Long datatypen. |
I följande exempel visas den potentiella obeslutsamheten hos flyttalsoperor.
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))
I föregående exempel används ToString metoden för Double strukturen så att den kan ange bättre precision än nyckelordet CStr
använder. Standardvärdet är 15 siffror, men formatet "G17" utökar det till 17 siffror.
Eftersom zeroPointTwo
är Double
är dess värde för 0,2 ett oändligt upprepande binärt bråk med ett lagrat värde på 0,20000000000001. Genom att dividera 2,0 med denna kvantitet ger det 9,9999999999999995 med återstoden 0,19999999999999991.
I uttrycket för decimalRemainder
tvingar literaltypen D
båda operanderna till Decimal
, och 0.2 har en exakt representation. Därför ger operatören Mod
den förväntade resten av 0,0.
Observera att det inte räcker att deklarera decimalRemainder
som Decimal
. Du måste också tvinga literalerna till Decimal
, eller så använder Double
de som standard och decimalRemainder
får samma felaktiga värde som doubleRemainder
.
Boolesk typ konverteras inte till numerisk typ korrekt
Booleska datatypvärden lagras inte som tal och de lagrade värdena är inte avsedda att motsvara tal. För kompatibilitet med tidigare versioner tillhandahåller Visual Basic konverteringsnyckelord (CType Function, CBool
, CInt
och så vidare) för att konvertera mellan Boolean
och numeriska typer. Andra språk utför dock ibland dessa konverteringar på olika sätt, liksom de .NET Framework metoderna.
Du bör aldrig skriva kod som förlitar sig på motsvarande numeriska värden för True
och False
. När det är möjligt bör du begränsa användningen av Boolean
variabler till de logiska värden som de är utformade för. Om du måste blanda Boolean
och numeriska värden ska du se till att du förstår vilken konverteringsmetod du väljer.
Konvertering i Visual Basic
När du använder nyckelorden eller konverteringen CType
för att konvertera numeriska datatyper till Boolean
blir False
0 och alla andra värden blir True
.CBool
När du konverterar Boolean
värden till numeriska typer med hjälp av konverteringsnyckelorden False
blir 0 och True
blir -1.
Konvertering i ramverket
Metoden ToInt32 för Convert klassen i System namnområdet konverteras True
till +1.
Om du måste konvertera ett Boolean
värde till en numerisk datatyp bör du vara försiktig med vilken konverteringsmetod du använder.
Teckenliteral genererar kompilatorfel
Om det inte finns några tecken av typen förutsätter Visual Basic standarddatatyper för literaler. Standardtypen för en teckenliteral – omgiven av citattecken (" "
) – är String
.
Datatypen String
utvidgas inte till teckendatatypen. Det innebär att om du vill tilldela en literal till en Char
variabel måste du antingen göra en begränsad konvertering eller tvinga literalen Char
till typen .
Så här skapar du en Char-literal som ska tilldelas till en variabel eller konstant |
---|
1. Deklarera variabeln eller konstanten som Char .2. Omge teckenvärdet inom citattecken ( " " ).3. Följ det avslutande dubbla citattecknet med teckentypen C literal för att tvinga literalen till Char . Detta är nödvändigt om typkontrollväxeln (Alternativ strikt instruktion) är On , och det är önskvärt i alla fall. |
I följande exempel visas både misslyckade och lyckade tilldelningar av en literal till en Char
variabel.
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")
Det finns alltid en risk med att använda begränsade konverteringar, eftersom de kan misslyckas vid körning. En konvertering från String
till kan till Char
exempel misslyckas om String
värdet innehåller mer än ett tecken. Därför är det bättre att programmera för att använda C
typtecknet.
Strängkonvertering misslyckas vid körning
Strängdatatypen deltar i mycket få bredare konverteringar. String
utvidgas endast till sig själv och Object
, och endast Char
och Char()
(en Char
matris) utvidgas till String
. Det beror på att String
variabler och konstanter kan innehålla värden som andra datatyper inte kan innehålla.
När typkontrollväxeln (Alternativ strikt instruktion) är On
tillåter kompilatorn inte alla implicita begränsade konverteringar. Detta inkluderar de som involverar String
. Koden kan fortfarande använda konverteringsnyckelord som CStr
och CType Function, som dirigerar .NET Framework att försöka konvertera.
Anteckning
Felet narrowing-conversion ignoreras för konverteringar från elementen i en For Each…Next
samling till loopkontrollvariabeln. Mer information och exempel finns i avsnittet "Begränsa konverteringar" i För varje... Nästa instruktion.
Begränsad konverteringsskydd
Nackdelen med att begränsa konverteringar är att de kan misslyckas vid körning. Om en String
variabel till exempel innehåller något annat än "Sant" eller "Falskt" kan den inte konverteras till Boolean
. Om den innehåller skiljetecken misslyckas konverteringen till en numerisk typ. Om du inte vet att variabeln String
alltid innehåller värden som måltypen kan acceptera bör du inte prova en konvertering.
Om du måste konvertera från String
till en annan datatyp är den säkraste proceduren att omsluta konverteringsförsöket i Try... Fånga... Slutligen -instruktion. På så sätt kan du hantera ett körningsfel.
Teckenmatriser
En enda Char
och en matris med Char
element som båda utvidgas till String
. Utvidgas dock String
inte till Char()
. Om du vill konvertera ett String
värde till en Char
matris kan du använda ToCharArray -metoden i System.String klassen .
Meningslösa värden
I allmänhet String
är värden inte meningsfulla i andra datatyper och konverteringen är mycket artificiell och farlig. När det är möjligt bör du begränsa användningen av String
variabler till de teckensekvenser som de är utformade för. Du bör aldrig skriva kod som förlitar sig på motsvarande värden i andra typer.