Delen via


Problemen met gegevenstypen oplossen (Visual Basic)

Deze pagina bevat enkele veelvoorkomende problemen die kunnen optreden wanneer u bewerkingen uitvoert op intrinsieke gegevenstypen.

Floating-Point-expressies worden niet vergeleken als gelijk

Wanneer u met getallen met drijvende komma werkt (enkel gegevenstype en dubbel gegevenstype), moet u er rekening mee houden dat deze als binaire breuken worden opgeslagen. Dit betekent dat ze geen exacte weergave kunnen bevatten van een hoeveelheid die geen binaire breuk is (van de vorm k / (2 ^ n), waarbij k en n gehele getallen zijn. 0,5 (= 1/2) en 0,3125 (= 5/16) kunnen bijvoorbeeld worden beschouwd als nauwkeurige waarden, terwijl 0,2 (= 1/5) en 0,3 (= 3/10) alleen benaderingen kunnen zijn.

Vanwege deze onnauwkeurigheid kunt u niet vertrouwen op exacte resultaten wanneer u met drijvendekommawaarden werkt. Met name twee waarden die theoretisch gelijk zijn, kunnen enigszins verschillende representaties hebben.

Drijvendekommahoeveelheden vergelijken
1. Bereken de absolute waarde van het verschil met behulp van de Abs methode van de Math klasse in de System naamruimte.
2. Bepaal een acceptabel maximumverschil, zodat u de twee hoeveelheden voor praktische doeleinden als gelijk kunt beschouwen als het verschil niet groter is.
3. Vergelijk de absolute waarde van het verschil met het acceptabele verschil.

In het volgende voorbeeld ziet u een onjuiste en juiste vergelijking van twee Double waarden.

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

In het vorige voorbeeld wordt de ToString methode van de Double structuur gebruikt, zodat deze een betere precisie kan opgeven dan het CStr trefwoord gebruikt. De standaardwaarde is 15 cijfers, maar de indeling 'G17' breidt deze uit tot 17 cijfers.

Mod-operator retourneert geen nauwkeurig resultaat

Vanwege de onnauwkeurigheid van drijvende-kommaopslag kan de operator Mod een onverwacht resultaat retourneren wanneer ten minste één van de operanden een drijvende komma is.

Het decimale gegevenstype maakt geen gebruik van drijvende-kommaweergave. Veel getallen die inexact Single zijn en Double exact zijn in Decimal (bijvoorbeeld 0,2 en 0,3). Hoewel rekenkundig langzamer Decimal is dan in drijvende komma, kan het de moeite waard zijn om de prestaties te verlagen om een betere precisie te bereiken.

Het gehele restgetal van drijvendekommagetalhoeveelheden zoeken
1. Declareer variabelen als Decimal.
2. Gebruik het letterlijke typeteken D om letterlijke waarden af te dwingen naar Decimal, voor het geval de waarden te groot zijn voor het Long gegevenstype.

In het volgende voorbeeld ziet u de mogelijke onnauwkeurigheid van operanden met drijvende komma.

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

In het vorige voorbeeld wordt de ToString methode van de Double structuur gebruikt, zodat deze een betere precisie kan opgeven dan het CStr trefwoord gebruikt. De standaardwaarde is 15 cijfers, maar de indeling 'G17' breidt deze uit tot 17 cijfers.

Omdat zeroPointTwo is Double, is de waarde voor 0,2 een oneindig herhalende binaire breuk met een opgeslagen waarde van 0,2000000000000000001. Het delen van 2,0 door deze hoeveelheid levert 9,9999999999999995 op met een rest van 0,19999999999999991.

In de expressie voor decimalRemainderdwingt het letterlijke type teken D beide operanden tot Decimal, en 0,2 heeft een nauwkeurige representatie. Daarom levert de Mod operator het verwachte restant van 0,0 op.

Houd er rekening mee dat het niet voldoende is om te declareren decimalRemainder als Decimal. U moet ook de letterlijke waarden afdwingen naar Decimal, of ze gebruiken Double standaard en decimalRemainder ontvangen dezelfde onnauwkeurige waarde als doubleRemainder.

Booleaans type converteert niet nauwkeurig naar numeriek type

Booleaanse gegevenstypewaarden worden niet opgeslagen als getallen en de opgeslagen waarden zijn niet bedoeld om gelijk te zijn aan getallen. Voor compatibiliteit met eerdere versies biedt Visual Basic conversietrefwoorden (CType-functie, CBool, CIntenzovoort) om te converteren tussen Boolean en numerieke typen. In andere talen worden deze conversies soms echter anders uitgevoerd, net als de .NET Framework-methoden.

Schrijf nooit code die afhankelijk is van equivalente numerieke waarden voor True en False. Indien mogelijk moet u het gebruik van Boolean variabelen beperken tot de logische waarden waarvoor ze zijn ontworpen. Als u numerieke waarden moet combineren Boolean , moet u ervoor zorgen dat u de conversiemethode begrijpt die u selecteert.

Conversie in Visual Basic

Wanneer u de CType conversietrefwoorden of CBool gebruikt om numerieke gegevenstypen te converteren naar Boolean, wordt False 0 en worden alle andere waarden True. Wanneer u waarden converteert Boolean naar numerieke typen met behulp van de conversietrefwoorden, False wordt 0 en True -1.

Conversie in het framework

De ToInt32 methode van de Convert klasse in de System naamruimte wordt geconverteerd True naar +1.

Als u een Boolean waarde moet converteren naar een numeriek gegevenstype, moet u voorzichtig zijn met de conversiemethode die u gebruikt.

Character Literal genereert compilerfout

Als er geen type tekens zijn, wordt in Visual Basic uitgegaan van standaardgegevenstypen voor letterlijke waarden. Het standaardtype voor een letterlijk teken, tussen aanhalingstekens (" ") , is String.

Het String gegevenstype wordt niet uitgebreid naar het gegevenstype Char. Dit betekent dat als u een letterlijke waarde wilt toewijzen aan een Char variabele, u een vernauwde conversie moet maken of de letterlijke waarde voor het Char type moet afdwingen.

Een letterlijk teken maken om toe te wijzen aan een variabele of constante
1. Declareer de variabele of constante als Char.
2. Plaats de tekenwaarde tussen aanhalingstekens (" ").
3. Volg het afsluitende dubbele aanhalingsteken met het letterlijke typeteken C om de letterlijke te forceren naar Char. Dit is nodig als de schakeloptie voor typecontrole (Option Strict Statement) is Onen in elk geval wenselijk is.

In het volgende voorbeeld ziet u zowel mislukte als geslaagde toewijzingen van een letterlijke aan een Char variabele.

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

Er is altijd een risico bij het gebruik van narrowing conversies, omdat deze tijdens runtime kunnen mislukken. Een conversie van String naar Char kan bijvoorbeeld mislukken als de String waarde meer dan één teken bevat. Daarom is het beter om te programmeren om het C typeteken te gebruiken.

Conversie van tekenreeks mislukt tijdens runtime

Het gegevenstype Tekenreeks neemt deel aan zeer weinig verbredingsconversies. String wordt alleen uitgebreid naar zichzelf en Object, en alleen Char en Char() (een Char matrix) breder naar String. Dit komt doordat String variabelen en constanten waarden kunnen bevatten die andere gegevenstypen niet kunnen bevatten.

Wanneer de schakeloptie voor typecontrole (Optie Strikte instructie) is On, staat de compiler alle impliciete narrowing-conversies niet toe. Dit geldt ook voor die met String. Uw code kan nog steeds conversietrefwoorden gebruiken, zoals CStr en CType Function, waarmee de .NET Framework de conversie probeert uit te voeren.

Notitie

De narrowing-conversiefout wordt onderdrukt voor conversies van de elementen in een For Each…Next verzameling naar de lusbesturingsvariabele. Zie de sectie Narrowing Conversions in For Each voor meer informatie en voorbeelden ... Volgende instructie.

Narrowing Conversion Protection

Het nadeel van het beperken van conversies is dat ze tijdens runtime kunnen mislukken. Als een String variabele bijvoorbeeld iets anders bevat dan 'Waar' of 'Onwaar', kan deze niet worden geconverteerd naar Boolean. Als deze interpunctietekens bevat, mislukt de conversie naar een willekeurig numeriek type. Tenzij u weet dat uw String variabele altijd waarden bevat die het doeltype kan accepteren, moet u geen conversie proberen.

Als u moet converteren van String naar een ander gegevenstype, is de veiligste procedure om de poging tot conversie in te sluiten in de Probeer... Vangen... Laatste verklaring. Hiermee kunt u een runtimefout afhandelen.

Tekenmatrices

Eén Char en een matrix met Char elementen worden beide breder tot String. Wordt echter String niet breder naar Char(). Als u een String waarde wilt converteren naar een Char matrix, kunt u de ToCharArray methode van de System.String klasse gebruiken.

Betekenisloze waarden

Over het algemeen String zijn waarden niet zinvol in andere gegevenstypen en is conversie zeer kunstmatig en gevaarlijk. Indien mogelijk moet u het gebruik van String variabelen beperken tot de tekenreeksen waarvoor ze zijn ontworpen. Schrijf nooit code die afhankelijk is van equivalente waarden in andere typen.

Zie ook