疑難排解資料類型 (Visual Basic)

此頁面列出當您對內建資料類型執行作業時可能發生的一些常見問題。

浮點運算式並未比較為相等

當您使用浮點數 (單一資料類型雙精確度資料類型) 時,請記住其會儲存為二進位分數。 這表示其不能保留確切表示任何不是 k / (2 ^) n 格式的二進位分數 (其中 k 和 n 是整數)。 例如,0.5 (= 1/2) 和 0.3125 (= 5/16) 可以保留為精確值,而 0.2 (= 1/5) 和 0.3 (= 3/10) 只能是近似值。

由於這種不精確,因此當您在浮點值上操作時,無法依賴確切的結果。 特別是,理論上相等的兩個值可能會有稍微不同的表示。

若要比較浮點數量
1. 使用 System 命名空間中 Math 類別的 Abs 方法,計算其差異的絕對值。
2. 判斷可接受的最大差異,如此一來,如果兩個數量的差異不較大,您可以將兩個數量視為相等。
3. 比較差異的絕對值與可接受的差異。

下列範例示範兩個 Double 值的不正確和正確比較。

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

上一個範例會使用 Double 結構的 ToString 方法,以便可以指定比 CStr 關鍵字使用的更佳精確度。 預設值為 15 位數,但「G17」格式會將其延伸至 17 位數。

Mod 運算子並未傳回精確的結果

由於浮點儲存的不精確,因此當至少有一個運算元是浮點時,Mod 運算子可能會傳回非預期的結果。

十進位資料類型不會使用浮點表示。 許多在 SingleDouble 中不精確的數字在 Decimal 中為精確 (例如 0.2 和 0.3)。 雖然算術在 Decimal 中的速度比浮點慢,但效能可能會降低,以達到更好的精確度。

尋找浮點數量的整數餘數
1. 將變數宣告為 Decimal
2. 使用常值型別字元 D 將常值強制為 Decimal,以防其值對 Long 資料類型而言太大。

下列範例示範浮點運算元可能出現的不精確。

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

上一個範例會使用 Double 結構的 ToString 方法,以便可以指定比 CStr 關鍵字使用的更佳精確度。 預設值為 15 位數,但「G17」格式會將其延伸至 17 位數。

因為 zeroPointTwoDouble,其 0.2 的值是無限重複的二進位分數,其儲存值為 0.20000000000000001。 將 2.0 除以此數量會產生 9.9999999999999995,餘數為 0.19999999999999991。

decimalRemainder 的運算式中,常值型別字元 D 會將兩個運算元都強制為 Decimal,而 0.2 具有精確的表示。 因此,Mod 運算子會產生預期的餘數 0.0。

請注意,其不足以宣告 decimalRemainderDecimal。 您也必須強制常值為 Decimal,否則其預設會使用 Double,而 decimalRemainder 會接收與 doubleRemainder 相同的不精確值。

布林值型別並未精確轉換成數值型別

布林值資料類型值不會儲存為數字,且儲存的值不等於數字。 為了與舊版相容,Visual Basic 提供轉換關鍵字 (CType 函式CBoolCInt 等),以在 Boolean 和數值型別之間轉換。 不過,其他語言有時會以不同的方式執行這些轉換,就像.NET Framework方法一樣。

您絕不應該撰寫依賴 TrueFalse 對等數值的程式碼。 您應該盡可能將 Boolean 變數的使用限制在當初所設計的邏輯值上。 如果您必須混合 Boolean 和數值,請確定您了解所選取的轉換方法。

Visual Basic 中的轉換

當您使用 CTypeCBool 轉換關鍵字將數值資料類型轉換成 Boolean 時,0 會變成 False ,而所有其他值都會變成 True。 當您使用轉換關鍵字將 Boolean 值轉換成數值型別時,False 會變成 0,而 True 會變成 -1。

Framework 中的轉換

System 命名空間中 Convert 類別的 ToInt32 方法會將 True 轉換成 +1。

如果您必須將 Boolean 值轉換成數值資料類型,請留意您使用的轉換方法。

字元常值產生編譯器錯誤

如果沒有任何類型字元,Visual Basic 會假設常值的預設資料類型。 字元常值的預設類型以引號 (" ") 括住,也就是 String

String 資料類型不會擴大為 Char 資料型別。 這表示如果您想要將常值指派給 Char 變數,則必須進行縮小轉換,或強制常值轉換為 Char 類型。

建立 Char 常值以指派給變數或常數
1. 將變數或常數宣告為 Char
2. 以引號 (" ") 括住字元值。
3. 在右邊雙引號結尾加上常值型別字元 C,將常值強制為 Char。 如果類型檢查參數 (Option Strict 陳述式) 是 On 則為必要,且在任何情況下都是必要的。

下列範例示範將常值指派給 Char 變數的失敗和成功。

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

使用縮小轉換時一律會有風險,因為其在執行階段可能會失敗。 例如,如果 String 值包含一個以上的字元,則從 String 轉換為 Char 會失敗。 因此,使用 C 類型字元是較佳的程式設計。

字串轉換在執行階段失敗

字串資料類型參與非常少的放大轉換。 String 只會放大至其本身和 Object,且只有 CharChar() (Char 陣列) 會放大為 String。 這是因為 String 變數和常數可以包含其他資料類型不能包含的值。

當類型檢查參數 (Option Strict 陳述式) 為 On 時,編譯器不允許所有隱含的縮小轉換。 這包括涉及 String 的轉換。 您的程式碼仍然可以使用 轉換關鍵字,例如 CStrCType 函式,以指示.NET Framework嘗試轉換。

注意

For Each…Next 集合中的項目轉換成迴圈控制項變數時,系統會隱藏縮小轉換錯誤。 如需詳細資訊和範例,請參閱 For Each...Next 陳述式中的「縮小轉換」一節。

縮小轉換保護

縮小轉換的缺點是可能會在執行階段失敗。 例如,如果 String 變數包含「True」或「False」以外的任何項目,則無法轉換成 Boolean。 如果包含標點符號字元,則轉換為任何數值型別都會失敗。 除非您知道 String 變數一律會保存目的地類型可接受的值,否則您不應該嘗試轉換。

如果您必須從 String 轉換成另一個資料類型,最安全的程序是將嘗試的轉換以 Try...Catch...Finally 陳述式括住。 這可讓您處理執行階段失敗。

字元陣列

單一 CharChar 項目的陣列會放大為 String。 不過,String 不會放大為 Char()。 若要將 String 值轉換成 Char 陣列,您可以使用 System.String 類別的 ToCharArray 方法。

無意義值

一般而言,String 值在其他資料類型中沒有意義,且轉換非常不自然且危險。 您應該盡可能將 String 變數的使用限制在當初所設計的字元序列上。 您絕不應該撰寫依賴其他類型中對等值的程式碼。

另請參閱