Dela via


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 decimalRemaindertvingar 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, CIntoch 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 Booleanblir 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 Ontillå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.

Se även