Řešení potíží s datovými typy (Visual Basic)

Tato stránka obsahuje některé běžné problémy, ke kterým může dojít při provádění operací s vnitřními datovými typy.

Floating-Point Výrazy se nesrovnávají jako rovny

Při práci s čísly s plovoucí desetinnou čárkou (jeden datový typ a datový typ Double) mějte na paměti, že jsou uloženy jako binární zlomky. To znamená, že nemohou obsahovat přesnou reprezentaci žádného množství, které není binární zlomek (ve tvaru k / (2 ^ n), kde k a n jsou celá čísla). Například hodnoty 0,5 (= 1/2) a 0,3125 (= 5/16) lze uchovávat jako přesné hodnoty, zatímco hodnoty 0,2 (= 1/5) a 0,3 (= 3/10) mohou být pouze přibližné hodnoty.

Z důvodu této nepřesné hodnoty se při práci s hodnotami s plovoucí desetinou čárkou nemůžete spoléhat na přesné výsledky. Konkrétně dvě hodnoty, které jsou teoreticky stejné, můžou mít mírně odlišné reprezentace.

Porovnání množství s plovoucí desetinou čárkou
1. Vypočítejte absolutní hodnotu jejich rozdílu Abs pomocí metody Math třídy v System oboru názvů.
2. Určete přijatelný maximální rozdíl tak, abyste mohli obě množství považovat za rovnanou pro praktické účely, pokud jejich rozdíl není větší.
3. Porovnejte absolutní hodnotu rozdílu s přijatelným rozdílem.

Následující příklad ukazuje nesprávné a správné porovnání dvou Double hodnot.

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

Předchozí příklad používá metodu ToStringDouble struktury, aby bylo možné zadat lepší přesnost, než CStr používá klíčové slovo . Výchozí hodnota je 15 číslic, ale formát "G17" ho rozšiřuje na 17 číslic.

Operátor Mod nevrací přesný výsledek

Z důvodu nepřesné úložiště s plovoucí desetinou čárkou může operátor Mod vrátit neočekávaný výsledek, pokud je alespoň jeden operand s plovoucí desetinou čárkou.

Datový typ Decimal nepoužívá reprezentaci s plovoucí desetinnou čárkou. Mnoho čísel, která jsou nepřesná v Single a Double jsou přesná ( Decimal například 0,2 a 0,3). I když je aritmetika pomalejší Decimal než hodnota s plovoucí desetinnou čárkou, může být snížení výkonu pro dosažení lepší přesnosti vhodné.

Vyhledání celočíselného zbytku množství s plovoucí desetinou čárkou
1. Deklarujte proměnné jako Decimal.
2. Použijte znak D literálového typu k vynucení literálů pro Decimal, pokud jsou jejich hodnoty pro Long datový typ příliš velké.

Následující příklad ukazuje potenciální nepřesné operandy s plovoucí desetinou čárkou.

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

Předchozí příklad používá metodu ToStringDouble struktury, aby bylo možné zadat lepší přesnost, než CStr používá klíčové slovo . Výchozí hodnota je 15 číslic, ale formát "G17" ho rozšiřuje na 17 číslic.

Protože zeroPointTwo je Double, jeho hodnota pro 0,2 je nekonečně se opakující binární zlomek s uloženou hodnotou 0,200000000000001. Vydělením čísla 2,0 tímto množstvím získáme 9,9999999999999999 se zbytkem 0,199999999999999991.

Ve výrazu pro decimalRemaindervynucuje znak D literálového typu oba operandy na Decimala 0.2 má přesné znázornění. Mod Operátor proto získá očekávaný zbytek hodnoty 0,0.

Všimněte si, že nestačí deklarovat decimalRemainder jako Decimal. Literály je také nutné vynutit, jinak Decimalpoužijí Double ve výchozím nastavení a decimalRemainder obdrží stejnou nepřesnou hodnotu jako doubleRemainder.

Logický typ se nepřevádí na číselný typ přesně

Logické hodnoty datového typu se neukládají jako čísla a uložené hodnoty nemají být ekvivalentní číslům. Z důvodu kompatibility s dřívějšími verzemi jazyka Visual Basic poskytuje klíčová slova převodu (funkce CType, CBool, CIntatd.) pro převod mezi Boolean a číselnými typy. Jiné jazyky však někdy provádějí tyto převody odlišně, stejně jako metody rozhraní .NET Framework.

Nikdy byste neměli psát kód, který se spoléhá na ekvivalentní číselné hodnoty pro True a False. Kdykoli je to možné, měli byste použití proměnných Boolean omezit na logické hodnoty, pro které jsou navrženy. Pokud potřebujete kombinovat Boolean číselné hodnoty a , ujistěte se, že vybrané metodě převodu rozumíte.

Převod v jazyce Visual Basic

Když k převodu CTypeCBool číselných datových typů Booleanpoužijete nebo , stane se False hodnota 0 a všechny ostatní hodnoty na True. Když převedete Boolean hodnoty na číselné typy pomocí klíčových slov převodu, False stane se hodnota 0 a True -1.

Převod v architektuře

Metoda ToInt32Convert třídy v System oboru názvů se převede True na +1.

Pokud potřebujete převést Boolean hodnotu na číselný datový typ, dávejte pozor na to, jakou metodu převodu použijete.

Chyba kompilátoru generuje znakový literál

Při absenci znaků typu předpokládá Visual Basic výchozí datové typy pro literály. Výchozí typ znakového literálu – uzavřený do uvozovek (" ") – je String.

Datový String typ se nerozšíře na datový typ Char. To znamená, že pokud chcete k proměnné přiřadit literál Char , musíte buď provést zužující převod, nebo vynutit literál na Char typ.

Vytvoření literálu Char pro přiřazení proměnné nebo konstantě
1. Deklarujte proměnnou nebo konstantu jako Char.
2. Hodnotu znaku uzavřete do uvozovek (" ").
3. Použijte uzavírací uvozovky se znakem C typu literálu, aby se literál vynutil na Char. To je nezbytné, pokud je přepínač kontroly typu (Option Strict Statement) Ona v každém případě je to žádoucí.

Následující příklad ukazuje neúspěšné i úspěšné přiřazení literálu Char k proměnné.

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

Použití zužující převody vždy představuje riziko, protože za běhu můžou selhat. Například převod z String na může selhat Char , pokud String hodnota obsahuje více než jeden znak. Proto je lepší programovat použití znaku C typu.

Převod řetězce selže za běhu

Datový typ String se účastní velmi málo rozšiřujících převodů. String rozšiřuje pouze na sebe a a Objectpouze Char a Char() ( Char pole) rozšiřuje na String. Je to proto, že String proměnné a konstanty mohou obsahovat hodnoty, které jiné datové typy nemohou obsahovat.

Pokud je Onpřepínač kontroly typu (Option Strict Statement) , kompilátor zakáže všechny implicitní zužující převody. To zahrnuje i ty, které zahrnují String. Váš kód může stále používat klíčová slova převodu, jako CStr je a funkce CType, která nasměrují rozhraní .NET Framework k pokusu o převod.

Poznámka

Chyba zužujícího převodu je potlačena pro převody z prvků v For Each…Next kolekci na řídicí proměnnou smyčky. Další informace a příklady najdete v části "Zužující převody" v tématu For Each... Next – příkaz.

Zužující ochrana převodu

Nevýhodou zúžení převodů je to, že za běhu můžou selhat. Pokud například proměnná String obsahuje cokoli jiného než "Pravda" nebo "Nepravda", nelze ji převést na Boolean. Pokud obsahuje interpunkční znaméne, převod na libovolný číselný typ se nezdaří. Pokud nevíte, že proměnná String vždy obsahuje hodnoty, které cílový typ může přijmout, neměli byste zkusit převod.

Pokud potřebujete převést z na String jiný datový typ, nejbezpečnějším postupem je uzavřít pokus o převod do pole Zkuste... Chytit... Příkaz Finally. To vám umožní řešit selhání za běhu.

Pole znaků

Jeden Char prvek a pole Char prvků se rozšiřují na String. Nevztahuje se String však na Char(). Chcete-li převést String hodnotu na Char pole, můžete použít metodu ToCharArraySystem.String třídy .

Bezvýznamné hodnoty

Obecně platí, že String hodnoty v jiných datových typech nejsou smysluplné a převod je vysoce umělý a nebezpečný. Kdykoli je to možné, měli byste použití proměnných String omezit na sekvence znaků, pro které jsou navrženy. Nikdy byste neměli psát kód, který spoléhá na ekvivalentní hodnoty v jiných typech.

Viz také