Delen via


Problemen met gegevenstypen oplossen (Visual Basic)

Op deze pagina vindt u enkele veelvoorkomende problemen die kunnen optreden wanneer u bewerkingen uitvoert op intrinsieke gegevenstypen.

Floating-Point expressies niet vergelijken als gelijk

Wanneer u werkt met drijvendekommagetalnummers (enkel gegevenstype en dubbel gegevenstype), moet u er rekening mee houden dat ze worden opgeslagen als binaire breuken. 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 als exacte waarden worden bewaard, 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 werkt met drijvendekommagewaarden. In het bijzonder kunnen twee waarden die theoretisch gelijk zijn, iets 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 kunt beschouwen als hun 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 wordt uitgebreid tot 17 cijfers.

Mod-operator retourneert geen nauwkeurig resultaat

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

Het gegevenstype Decimaal gebruikt geen drijvendekommagepresentatie. Veel getallen die inexact Single zijn en Double exact zijn Decimal in (bijvoorbeeld 0,2 en 0,3). Hoewel rekenkundige berekeningen langzamer Decimal zijn dan in drijvende komma, is het misschien de moeite waard om de prestaties te verlagen om betere precisie te bereiken.

Het gehele getal van drijvendekommagetale hoeveelheden zoeken
1. Variabelen declareren als Decimal.
2. Gebruik het letterlijke type teken D om letterlijke waarden af Decimalte dwingen, 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 wordt uitgebreid tot 17 cijfers.

Omdat zeroPointTwo is Double, de waarde voor 0,2 is een oneindig herhalende binaire breuk met een opgeslagen waarde van 0,20000000000000000001. De verdeling van 2,0 door deze hoeveelheid resulteert in 9,9999999999999995 met een rest van 0,1999999999999999991.

In de expressie voor decimalRemainder, het letterlijke type teken D dwingt beide operanden aan Decimalen 0,2 heeft een exacte weergave. Mod De operator levert daarom de verwachte rest van 0,0 op.

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

Booleaanse waarde wordt niet nauwkeurig geconverteerd 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 Operator, CBoolCIntenzovoort) om te converteren tussen Boolean en numerieke typen. In andere talen worden deze conversies echter soms anders uitgevoerd, net als de .NET Framework-methoden.

U moet nooit code schrijven die afhankelijk is van gelijkwaardige 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 waarden en 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 trefwoorden of CBool conversietrefwoorden 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 wordt -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.

Letterlijk teken genereert compilerfout

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

Het String gegevenstype wordt niet uitgebreid naar het gegevenstype Teken. Dit betekent dat als u een letterlijke entiteit wilt toewijzen aan een Char variabele, u een beperkte conversie moet maken of de letterlijke gegevens naar het Char type wilt forceren.

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 dubbele aanhalingsteken sluiten met het letterlijke type teken C om de letterlijke aanhalingsteken af te Chardwingen. Dit is noodzakelijk als de typecontroleschakelaar (optie strikte instructie) is Onen het 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 bestaat altijd een risico bij het gebruik van narrowing-conversies, omdat ze tijdens runtime kunnen mislukken. Een conversie van String naar kan Char bijvoorbeeld mislukken als de String waarde meer dan één teken bevat. Daarom is het beter programmeren om het C type teken te gebruiken.

Conversie van tekenreeks mislukt tijdens runtime

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

Wanneer de schakeloptie typecontrole (Optie strikt instructie) is On, wordt alle impliciete vermalingsconversies door de compiler niet toegezegd. Dit geldt ook voor de betrokkenen String. Uw code kan nog steeds conversietrefwoorden gebruiken, zoals CStr en CType Operator, die het .NET Framework omsturen om de conversie uit te voeren.

Opmerking

De narrowing-conversiefout wordt onderdrukt voor conversies van de elementen in een For Each…Next verzameling naar de lusbesturingselementvariabele. 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 leestekens bevat, mislukt de conversie naar een numeriek type. Tenzij u weet dat uw String variabele altijd waarden bevat die door het doeltype kunnen worden geaccepteerd, moet u geen conversie proberen.

Als u moet converteren van String naar een ander gegevenstype, is de veiligste procedure het insluiten van de geprobeerde conversie in de Try... Vangen... Tot slot verklaring. Hiermee kunt u een runtimefout afhandelen.

Tekenmatrices

Char Eén en een matrix van Char elementen die beide breder worden.String Echter, String wordt 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 de conversie is zeer kunstmatig en gevaarlijk. Indien mogelijk moet u het gebruik van String variabelen beperken tot de tekenreeksen waarvoor ze zijn ontworpen. U moet nooit code schrijven die afhankelijk is van gelijkwaardige waarden in andere typen.

Zie ook